久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1374|回復: 1
打印 上一主題 下一主題
收起左側

求指點STM32 RS485發送幀數據更好的方法 附源程序

[復制鏈接]
跳轉到指定樓層
樓主
不知道是不是因為我的方法不合理,使用了while()循環來485發送幀數據的時候,數碼管會閃爍,普通串口不會,不知道問題是不是在while()這里。

//485收發上圖:

貼代碼(stm32f103ret6):
//main.c
#include "stm32f10x.h"                  // Device header
#include "LED.H"
#include "DISPLAY.H"
#include "TIMER.H"
#include "USART.H"
#include "RS485.H"

int main(void)
{
        LED_Init();
        DISPLAY1_Init();
        KEY_Init();
        INTERRUPT_Init();
        Timer_Init();
        USART1_Init();
        RS485_Init();
        
        while (1)
        {
               
        }        
}



//rs485.h
#ifndef __RS485_H
#define __RS485_H

void RS485_Init(void);

extern unsigned int Uart4_Rx;
extern unsigned char Uart4_Buffer[ ];
extern uint16_t Uart4_Tx_Num;

#endif


//rs485.c
#include "stm32f10x.h"                  // Device header
#include "DISPLAY.H"
        //RS485(UART4) : TX/PC10; RX/PC11; DE/PA12。
void RS485_Init(void)
{
                //GPIO_配置UART4_DE(PA12);并初始化為低電平,UART4_485為接收模式。
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        //開啟對應GPIO_時鐘
        GPIO_InitTypeDef GPIO_InitStructure;        //定義GPIO_結構體
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;               
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_ResetBits(GPIOA, GPIO_Pin_12);        //初始化UART4_DE為低電平,UART4_485默認為接收模式。
                //GPIO_配置UART4_TX(PC10)
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);        //開啟對應GPIO_時鐘
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitStructure);        
                //GPIO_配置UART4_RX(PC11)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
        
                //USART_配置UART4(波特率9600,長度8字節,1停止位,0奇偶校驗位,0硬件流控制)
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);        //開啟對應USART_時鐘
        USART_InitTypeDef USART_InitStructure;        //定義USART_結構體
        USART_InitStructure.USART_BaudRate = 9600;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No ;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                //使能發送與接收功能
        USART_Init(UART4, &USART_InitStructure);
        USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);        //接收中斷,使能
        USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);        //空閑總線中斷,使能
        USART_Cmd(UART4, ENABLE);        //使設定的配置生效,但在STM32里,需要配合對應的時鐘使用
        
                //NVIC_配置UART4(優先級分組2,搶占優先級為1,響應優先級為1)
        NVIC_InitTypeDef NVIC_InitStructure;        //定義NVIC_結構體
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                                   
        NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;  
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
        NVIC_Init(&NVIC_InitStructure);                                 
}

#define Max_BUFF_Len_4 18
unsigned char Uart4_Buffer[ Max_BUFF_Len_4 ];

unsigned int Uart4_Rx = 0;
void UART4_ReceiveData(void)
{
        if(USART_GetITStatus (UART4,USART_IT_RXNE))                //接收中斷
        {
                Uart4_Buffer[ Uart4_Rx ] = USART_ReceiveData(UART4);
                Uart4_Rx ++;
                if(Uart4_Rx >=201)        //防止達數組上限
                {
                        Uart4_Rx = 0;
                }
        }
}

uint16_t Uart4_Tx_Num =0;
void UART4_TX(void)
{
        static uint32_t Clear;
        if(USART_GetITStatus (UART4,USART_IT_IDLE))                //總線空閑中斷   
        {
                while(Uart4_Rx >=1)                //485循環發送數組Uart4_Buffer[ ]內的數,解決只一次發送的問題
                {
                        GPIO_SetBits(GPIOA, GPIO_Pin_12);        //485發送使能
                        USART_SendData(UART4,Uart4_Buffer[ Uart4_Tx_Num ]);
                        Uart4_Tx_Num ++;        //485發送順序從數組Uart4_Buffer[ 0-100 ]
                        while(USART_GetFlagStatus (UART4,USART_FLAG_TC) !=1);
                        if(Uart4_Tx_Num == Uart4_Rx )        //        待發送完成
                        {
                                Uart4_Rx = 0;
                                Uart4_Tx_Num = 0;
                        }
                }
                if(Uart4_Rx ==0)
                {
                        Clear = UART4->SR;        //跳出總線空閑中斷
                        Clear = UART4->DR;        //跳出總線空閑中斷
                        GPIO_ResetBits(GPIOA, GPIO_Pin_12);
                }
        }
}

void UART4_IRQHandler(void)
{
        UART4_ReceiveData();
        UART4_TX();
        
        USART_ClearFlag (UART4,USART_FLAG_TC);
}



//usart.h
#ifndef __USART_H
#define __USART_H

void USART1_Init(void);

extern unsigned int Usart1_Rx;
extern unsigned char Usart1_Buffer[ ];


#endif


//usart.c
#include "stm32f10x.h"   

        //USART1 : TX/PA9; RX/PA10。
void USART1_Init(void)
{
                //GPIO_配置USART1_TX(PA9)               
        RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA ,ENABLE );          //GPIOA時鐘開啟
        GPIO_InitTypeDef GPIO_InitInstructure;        
        GPIO_InitInstructure.GPIO_Mode = GPIO_Mode_AF_PP;          //選擇引腳模式,TX 需配置為:_AF_PP(復用推挽輸出,用作串口的輸出)
        GPIO_InitInstructure.GPIO_Pin = GPIO_Pin_9;          //選擇引腳
        GPIO_InitInstructure.GPIO_Speed = GPIO_Speed_50MHz;          //選擇引腳頻率
        GPIO_Init(GPIOA,&GPIO_InitInstructure );        //進行參數初始化
                //GPIO_配置USART1_RX(PA10)
        GPIO_InitInstructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;          //選擇引腳模式,RX 需配置為:_IN_FLOATING(浮空輸入,由于其輸入阻抗比較大,一般把這種模式用于標準的通訊協議,比如IIC、USART等)
        GPIO_InitInstructure.GPIO_Pin = GPIO_Pin_10;          //選擇引腳
        GPIO_InitInstructure.GPIO_Speed = GPIO_Speed_50MHz;          //RX引腳,也可以不配置引腳頻率
        GPIO_Init(GPIOA,&GPIO_InitInstructure );        //進行參數初始化
        
                //USART_配置USART1(波特率9600,長度8字節,1停止位,0奇偶校驗位,0硬件流控制)
        RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 ,ENABLE );        //串口USART1時鐘開啟
        USART_InitTypeDef USART_InitInstructure;
        USART_InitInstructure.USART_BaudRate = 9600;        //直接修改波特率即可
        USART_InitInstructure.USART_WordLength = USART_WordLength_8b;        //長度 8字節
        USART_InitInstructure.USART_StopBits = USART_StopBits_1;        //1位 停止位
        USART_InitInstructure.USART_Parity = USART_Parity_No;        //無 奇偶校驗位
        USART_InitInstructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;        //無 硬件流控制
        USART_InitInstructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //使能發送與接收功能
        USART_Init(USART1,&USART_InitInstructure);
        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);        //接收中斷,使能
        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);        //總線空閑中斷,使能               
        USART_Cmd (USART1 ,ENABLE );        //使設定的配置生效,但在STM32里,需要配合對應的時鐘使用

                //NVIC_配置USART1(優先級分組2,搶占優先級為2,響應優先級為2)
        NVIC_InitTypeDef NVIC_InitStructure;        
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;        //從stm32f10x.h里第243-268行選擇
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          //
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;        //搶占優先級為2
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;        //響應優先級為2
        NVIC_Init(&NVIC_InitStructure);          //進行參數初始化
}

#define Max_BUFF_Len_1 18
unsigned char Usart1_Buffer[ Max_BUFF_Len_1 ];

unsigned int Usart1_Rx = 0;

void USART1_IRQHandler(void)
{
        if(USART_GetITStatus (USART1,USART_IT_RXNE))        //接收中斷
        {
                Usart1_Buffer[ Usart1_Rx ] = USART_ReceiveData(USART1);
                Usart1_Rx ++;
               
                USART_SendData(USART1,Usart1_Buffer[ Usart1_Rx -1 ]);  //接收完立即發
               
                Usart1_Rx = 0;
        }
        
        USART_ClearFlag (USART1,USART_FLAG_TC);
}



//TIMER.H
#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
void TIM2_IRQHandler(void);

extern uint16_t k;


#endif


//TIMER.c
#include "stm32f10x.h"                  // Device header
#include "DISPLAY.H"

void Timer_Init(void)
{
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //開啟TIM2時鐘
        
        TIM_InternalClockConfig(TIM2);        //
        //計數器溢出頻率CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)
        //內部時鐘默認為72M,此處選用內部時鐘頻率的話
        //若設置為72M/(7200-1 +1) /(10000-1 +1) = 1秒,即:1秒進中斷一次。
        //結構體(TIM_TimeBaseInitStructure),在本函數內定義一次即可
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;         //
        TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;          //濾波采樣分頻系數,1/2/4分頻。它影響的是濾波器的采樣(輸入)頻率,與輸出無關
        TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;          //TIM向上計數模式
        TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;          //定時器預分頻器設置,可設置范圍為 0 至 65535,實現 1 至 65536 分頻,內部自動+1。        
        TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;        //定時器周期,設定自動重載寄存器的值,在事件生成時更新到影子寄存器。可設置范圍為 0 至 65535,內部自動+1。
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;        //高級定時器才有的。周期倍數:n+1倍。此處為0時,即1倍周期1s;為1時即2倍周期2s,n最大為225(0XFF)。
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);         //初始化參數(TIM)
        
        TIM_ClearFlag(TIM2, TIM_FLAG_Update);        //清除更新中斷,避免一打開中斷就立刻產生中斷
        TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);         //打開定時器更新中斷
        
                //前提條件1:組別優先順序(第0組優先級最強,第4組優先級最弱):NVIC_PriorityGroup_0>NVIC_PriorityGroup_1>NVIC_PriorityGroup_2>NVIC_PriorityGroup_3>NVIC_PriorityGroup_4
                //前提條件2:不同組優先級別間,依據優先級強弱,優先級別高的組,其中斷源可以打斷優先級別低的組的正在做的事情;(即:不同組優先級間,可以中斷嵌套)
                //前提條件3:組優先級別>搶占優先級別>響應優先級別
                //前提條件4:搶占優先級越小,優先級越高;但同組優先級不能相互打斷,也就沒有中斷嵌套
                //前提條件5:響應優先級越小的中斷首先執行(不能嵌套),如果響應優先級也均相同,則根據各中斷對應向量表的位置來確定,向量表中越靠前的中斷先響應
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);          //函數優先級分組配置,共5組(0-4),此處為第1組。
        
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;          //選擇EXTI2中斷 ,對應之前開啟的TIM2時鐘
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能EXTI2中斷
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;        //搶占優先級
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;         //響應優先級
        NVIC_Init(&NVIC_InitStructure);          //初始化參數(NVIC)
        
        TIM_Cmd(TIM2, ENABLE);         //使能TIM2外設
}

uint16_t k = 1;

void TIM2_IRQHandler(void)
{
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)        //檢查指定的TIM中斷發生與否
        {
                k ++;
                if(k >= 40)
                {
                        k = 1;
                }
                Display();
               
                TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                //清除TIM2的中斷待處理位
        }
}



//display.h
#ifndef __DISPLAY_H
#define __DISPLAY_H

void DISPLAY1_Init(void);
void Display(void);


extern uint16_t n;
extern uint16_t p;

#endif


//display.c
#include "stm32f10x.h"                  // Device header
#include "TIMER.H"
#include "USART.H"
#include "RS485.H"

void DISPLAY1_Init(void)        //初始化時可以設置為默認完全打開功能,檢測硬件是否OK
{
        //PB4:SGE1(位選1);PB3:SEG2(位選2)
        //PC13:a;PC14:b;PC15:c;PC1:d;
        //PC3:e;PA2:f;PA3:g;PC0:dp。
        //GPIO_Write(GPIOC, 0xE00B);
        //GPIO_Write(GPIOA,0x000C);
        //共陰數碼管:所有陰極(負極)連在(并在)一起。共陽同理。        
                //結構體:
        GPIO_InitTypeDef GPIO_InitStructure;        //定義結構體GPIO_InitStructure,用它來傳遞數據
                //STM32F10x系列的MCU復位后,PA13/14/15 & PB3/4默認配置為JTAG功能。有時我們為了充分利用MCU I/O口的資源,會把這些端口設置為普通I/O口
               
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);        //使能相應GPIOB端口時鐘以及AFIO功能時鐘(復用時鐘),在使用時開啟,一方面可以降低功耗;
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);         
                //枚舉類型:規范、限制變量賦值、取值范圍,使其不能隨意取值。
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;        //選擇引腳模式,結構體GPIO_InitStructure內枚舉類型GPIO_Mode賦值        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4 ;        //選擇引腳,結構體GPIO_InitStructure內枚舉類型GPIO_Pin賦值
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //選擇引腳頻率,結構體GPIO_InitStructure內枚舉類型GPIO_Speed賦值
        GPIO_Init(GPIOB,&GPIO_InitStructure);        //進行參數初始化(GPIOB), &:取地址符號,這里使用地址傳遞
        
//        GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);         //賦值,數碼管高電平有效,非初始化必需步驟
        
        RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC ,ENABLE );
        GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;
        GPIO_InitStructure .GPIO_Pin =GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13|GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz ;
        GPIO_Init (GPIOC,&GPIO_InitStructure );
        
//        GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3|GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13);        //高電平有效
        
        RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA,ENABLE );
        GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP ;
        GPIO_InitStructure.GPIO_Pin =GPIO_Pin_2|GPIO_Pin_3 ;
        GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        
//        GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3);
}

uint16_t p;
uint16_t n;
        //通過定時器內k(1-40)的自增循環,來進行數碼管的點亮刷新
void Display(void)
{
        if(k >= 1 && k <= 19 )
        {
                GPIO_Write(GPIOB, 0x0010 );  //數碼管位選1
        }
        if(k >= 20 && k <= 39)
        {
                GPIO_Write(GPIOB, 0x0008 );  //數碼管位選2
        }                                
                //0-9
        const uint16_t num_table_1[] = {0xE00A,0xC000,0x600A,0xE002,0xC000,0xA002,0xA00A,0xE000,0xE00A,0xE002};                //,0x0001
        const uint16_t num_table_2[] = {0x0004,0x0000,0x0008,0x0008,0x000C,0x000C,0x000C,0x0000,0x000C,0x000C};                //,0x0000
                p= 1;//Uart4_Rx / 10 %10 ;
                n= 2;//Uart4_Rx % 10;
        if(GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_4) == 1)
        {
                GPIO_Write(GPIOC, num_table_1[p] );
                GPIO_Write(GPIOA, num_table_2[p] );                        
        }
        if(GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_3) == 1)
        {
                GPIO_Write(GPIOC, num_table_1[n] );
                GPIO_Write(GPIOA, num_table_2[n] );                        
        }
}
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:301191 發表于 2022-3-12 01:35 | 只看該作者
頂一下
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 成人免费淫片aa视频免费 | 日日骚视频 | 久久精品小短片 | 亚洲国产小视频 | 日韩中文字幕视频 | 国产精久久久 | 亚洲精品久久久久国产 | 国精品一区二区 | 成人欧美一区二区三区黑人孕妇 | 成人性视频在线播放 | 亚洲视频在线看 | 久久精品国产一区 | 风间由美一区二区三区在线观看 | 国产伦精品一区二区三区精品视频 | 在线不卡视频 | 日本高清视频在线播放 | 国产亚洲精品久久久久久牛牛 | 久草日韩| 日韩电影一区二区三区 | 欧美在线视频观看 | 不卡一区二区三区四区 | 欧美日韩国产高清视频 | 日本免费黄色一级片 | 久久国产亚洲 | 成人精品一区二区三区中文字幕 | 亚洲欧美国产毛片在线 | 一级毛片黄片 | 久久国产精品99久久久久 | 伊人久久综合 | 亚洲日韩中文字幕一区 | 天天草天天射 | 亚洲欧美一区二区三区情侣bbw | 久久99精品视频 | 在线日韩视频 | 久久国产精品视频 | 亚洲精品www| 成人自拍av | 中文字幕第二区 | 久久天天 | 超碰97免费观看 | 免费在线h视频 |