軟件設計
代碼如下:
//初始化 IO 串口 1
//bound:波特率
void uart_init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//①串口時鐘使能,GPIO 時鐘使能,復用時鐘使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|
RCC_APB2Periph_GPIOA, ENABLE); //使能 USART1,GPIOA 時鐘
//②串口復位
USART_DeInit(USART1); //復位串口 1
//③GPIO 端口模式設置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //ISART1_TX PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1_RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10
//④串口參數初始化
USART_InitStructure.USART_BaudRate = bound; //波特率設置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長為 8 位
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(USART1, &USART_InitStructure); //初始化串口
#if EN_USART1_RX //如果使能了接收
//⑤初始化 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //搶占優先級 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //中斷優先級初始化
//⑤開啟中斷
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啟中斷
#endif
//⑥使能串口
USART_Cmd(USART1, ENABLE); //使能串口
}
此代碼的編寫順序即USART的配置順序:
我們用標號①~⑥標 示了順序:
① 串口時鐘使能,GPIO 時鐘使能
② 串口復位
③ GPIO 端口模式設置
④ 串口參數初始化
⑤ 初始化 NVIC 并且開啟中斷
⑥ 使能串口
配置全雙工的串口 1,那么 TX(PA9) 管腳需要配置為推挽復用輸出,RX(PA10)管腳配置為浮空輸入或者帶上拉輸入。
模式配置參考下面表格:
使用了串口的中斷接收,必須在 usart.h 里面設置 EN_USART1_RX 為 1(默認設置就是 1 的) 。該函數才會配置中斷使能,以及開啟串口 1 的 NVIC 中斷。這里我們把串口 1 中斷放在組 2,優先級設置為組 2 里面的最低。
接下來,根據之前講解的步驟 7,還要編寫中斷服務函數。串口 1 的中斷服務函數 USART1_IRQHandler。
USART1_IRQHandler 函數
void USART1_IRQHandler(void)函數是串口 1 的中斷響應函數,當串口 1 發生了相應的中斷后,就會跳到該函數執行。中斷相應函數的名字是不能隨便定義的,一般我們都遵循 MDK定義的函數名。這些函數名字在啟動文件 startup_stm32f10x_hd.s 文件中可以找到。
函數體里面通過函數:
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
判斷是否接受中斷,如果是串口接受中斷,則讀取串口接受到的數據:
Res =USART_ReceiveData(USART1);//(USART1->DR); //讀取接收到的數據
讀到數據后接下來就對數據進行分析。
這里我們設計了一個小小的接收協議:通過這個函數,配合一個數組 USART_RX_BUF[],一個接收狀態寄存器 USART_RX_STA(此寄存器其實就是一個全局變量,由作者自行添加。由于它起到類似寄存器的功能,這里暫且稱之為寄存器)實現對串口數據的接收管理。
USART_RX_BUF 的大小由 USART_REC_LEN 定義,也就是一次接收的數據最大不能超過USART_REC_LEN 個字節。USART_RX_STA 是一個接收狀態寄存器其各的定義如表 5.3.1.1 所示:
設計思路如下:
當接收到從電腦發過來的數據,把接收到的數據保存在 USART_RX_BUF 中,同時在接收狀態寄存器(USART_RX_STA)中計數接收到的有效數據個數,當收到回車(回車的表示由 2個字節組成:0X0D 和 0X0A)的第一個字節 0X0D 時,計數器將不再增加,等待 0X0A 的到來,而如果 0X0A 沒有來到,則認為這次接收失敗,重新開始下一次接收。
如果順利接收到 0X0A,則標記 USART_RX_STA 的第 15 位,這樣完成一次接收,并等待該位被其他程序清除,從而開始下一次的接收,而如果遲遲沒有收到 0X0D,那么在接收數據超過 USART_REC_LEN 的時候,則會丟棄前面的數據,重新接收。
中斷相應函數代碼如下:
void USART1_IRQHandler(void) //串口1中斷服務程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
{
Res =USART_ReceiveData(USART1); //讀取接收到的數據
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重新開始接收
}
}
}
}
}
main.c中的代碼
int main(void)
{
u16 t;
u16 len;
u16 times=0;
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
uart_init(115200); //串口初始化為115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化與按鍵連接的硬件接口
while(1)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的數據長度
printf("\\r\\n您發送的消息為:\\r\\n\\r\\n");
for(t=0;t<len;t++)
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1發送數據
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待發送結束
}
printf("\\r\\n\\r\\n");//插入換行
USART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf("\\r\\n精英STM32開發板 串口實驗\\r\\n");
printf("正點原子@ALIENTEK\\r\\n\\r\\n");
}
if(times%200==0)printf("請輸入數據,以回車鍵結束\\n");
if(times%30==0)LED0=!LED0;//閃爍LED,提示系統正在運行.
delay_ms(10);
}
}
}
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)函數, 該函數是設置中斷分組號為 2,也就是 2 位搶占優先級和 2 位子優先級。
USART_SendData(USART1, USART_RX_BUF[t]); //向串口 1 發送數據
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
第一句,其實就是發送一個字節到串口。
第二句,就是我們在我們發送一個數據到串口之后,要檢測這個數據是否已經被發送完成了。USART_FLAG_TC 是宏定義的數據發送完成標識符。
下載驗證
首先打開串口調試助手。任何一個串口調試助手都是可以的。正點原子中使用的是舊版本的XCOM2.0。
我們在程序上 面設置了必須輸入回車,串口才認可接收到的數據,所以必須在發送數據后再發送一個回車符, 這里 XCOM 提供的發送方法是通過勾選發送新行實現。
只要勾選了這個選項,每次發送數據后,XCOM 都會自動多發一個回車(0X0D+0X0A)。設置好了發送新行,我們再在發送區輸入你想要發送的文字,然后單擊發送,就能實現發送數據。
發送的數據被打印出來了,說明實驗成功。
-
串口通訊
+關注
關注
1文章
260瀏覽量
24967 -
通訊協議
+關注
關注
10文章
276瀏覽量
20370 -
串行通訊
+關注
關注
2文章
77瀏覽量
16389
發布評論請先 登錄
相關推薦
評論