第一次深入學習stm32,花了好長時間才看懂代碼(主要是C語言學習不夠深入),又花了段時間自己敲了一遍,然後比對教程,瞭解了利用中斷來串口通信的設置方法。 板子是探索版f407,本實驗工程把正點原子庫函數工程模版拿來使用,自己主要敲了一下main.c、usart.h和.c文件。 一、頭文件usart ...
第一次深入學習stm32,花了好長時間才看懂代碼(主要是C語言學習不夠深入),又花了段時間自己敲了一遍,然後比對教程,瞭解了利用中斷來串口通信的設置方法。
板子是探索版f407,本實驗工程把正點原子庫函數工程模版拿來使用,自己主要敲了一下main.c、usart.h和.c文件。
一、頭文件usart.h
1 #ifndef __USART_H //定義同時防止重覆定義 2 #define __USART_H 3 4 #include "stdio.h" 5 #include "stm32f4xx_conf.h" 6 #include "sys.h" 7 8 #define USART_REC_LEN 200 //最大接收位元組數 9 #define EN_USART1_RX 1 //(1)使能串口接收 10 11 12 /*extern外部聲明引用這個變數,在.c文件尋找。*/ 13 extern u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大位元組為USART_REC_LEN,末字元為換行符 14 extern u16 USART_RX_STA; //接收狀態標記 15 void uart_init(u32 bound); //.c文件裡面的函數聲明 16 17 #endif
頭文件主要是其他文件需要用到的一些參數()的巨集定義及聲明,加.c文件的函數
二、usart.c文件
1、所需要的頭文件
2、定義參數並且使能串口接收
3、uart_init(u32 bound) //主函數調用設置波特率
參數結構:GPIO/USART/NVIC.InitSturcture
a,使能GPIOA和USART1時鐘,它們分別掛在在AHB1和APB2。
b,GPIOA的PA9和PA10復用為USART1。
c,串口1復用對應的IO口設置
d,串口1初始化設置(波特率、字長、停止位、奇偶、硬體流、模式)
e,使能串口1USART_Cmd(x,x)
f,巨集定義
#if 條件
USART_ITConfig( )開啟中斷
設置中斷通道、優先順序、子優先順序、IRQ使能
初始化NVIC_Init( )
4、串口1中斷服務函數(當一個位元組數據接收到,會觸發中斷,該函數處理中斷)
USART_IRQHandler()
參數USART_RX_STA是上一次累計的位元組接收量,Res是這一次接收的一個位元組數據
1 #include "sys.h" 2 #include "usart.h" 3 4 //加入以下代碼,支持printf函數,而不需要選擇use MicroLIB 5 #if 1 6 #pragma import(__use_no_semihosting) 7 //標準庫需要的支持函數 8 struct __FILE 9 { 10 int handle; 11 }; 12 13 FILE __stdout; 14 //定義_sys_exit()以避免使用半主機模式 15 _sys_exit(int x) 16 { 17 x = x; 18 } 19 //重定義fputc函數 20 int fputc(int ch, FILE *f) 21 { 22 while((USART1->SR&0X40)==0);//迴圈發送,直到發送完畢 23 USART1->DR = (u8) ch; 24 return ch; 25 } 26 #endif 27 28 #if EN_USART1_RX 29 u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大位元組為USART_REC_LEN,末字元為換行符 30 u16 USART_RX_STA=0; //接收狀態標記初始化為0 31 32 33 34 void uart_init(u32 bound) 35 { 36 GPIO_InitTypeDef GPIO_InitStructure; 37 USART_InitTypeDef USART_InitStructure; 38 NVIC_InitTypeDef NVIC_InitStructure; 39 40 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能gpioa的時鐘 41 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1時鐘 42 43 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//復用為USART1 44 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//復用為USART1 45 46 //串口1復用對應的 47 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; 48 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 49 GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz; 50 GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;//復用推輓 51 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 52 GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化 53 54 USART_InitStructure.USART_BaudRate=bound;//設置波特率 55 USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字長 56 USART_InitStructure.USART_StopBits=USART_StopBits_1;//停止位 57 USART_InitStructure.USART_Parity=USART_Parity_No;//無奇偶校驗 58 USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//發送接收模式 59 USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//無硬體流控制 60 USART_Init(USART1, &USART_InitStructure);//初始化串口 61 62 USART_Cmd(USART1,ENABLE);//使能串口1 63 64 #if EN_USART1_RX //開啟串口接收相關的中斷 65 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); 66 67 NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;//串口1中斷通道 68 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中斷通道 69 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; 70 NVIC_InitStructure.NVIC_IRQChannelSubPriority=3; 71 72 NVIC_Init(&NVIC_InitStructure); 73 74 #endif 75 76 } 77 78 /*串口1中斷服務函數,接收到一個數據就產生一次中斷,當接收到兩次數據為0X0D和OXOA時, 79 USART_RX_STA最高位置1,此時main函數while迴圈執行。*/ 80 81 void USART1_IRQHandler(void) 82 { 83 u8 Res; 84 if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)//接收中斷 85 { 86 Res=USART_ReceiveData(USART1); 87 if((USART_RX_STA&0x8000)==0) 88 { 89 if(USART_RX_STA&0x4000) 90 { 91 if(Res==0x0a) 92 { 93 USART_RX_STA|=0x8000;//將bit15位置1,此時main函數while迴圈裡面的判斷生效。 94 } 95 else 96 { 97 USART_RX_STA=0;//上一次標誌位bit14置1,此次數據不為0x0a,說明輸入錯誤,只有整段數據末尾為0x0d,0x0a數據才有效。 98 } 99 } 100 else 101 { 102 if(Res==0x0d) 103 { 104 USART_RX_STA|=0x4000;}//這次數據為0x0d,將bit14位置1。 105 else 106 { 107 USART_RX_STA++; 108 USART_RX_BUF[USART_RX_STA]=Res; 109 110 if(USART_RX_STA >USART_REC_LEN-1) //如果接收到的長度大於規定的長度,說明發送錯誤,狀態清零。 111 USART_RX_STA=0; 112 } 113 } 114 } 115 } 116 } 117 #endif
三、main.c
頭文件
定義參數t,len(發送長度),times(時間參數)
設置系統中斷優先順序分組2
初始化延時、串口(波特率)
while(1)
{
if判斷USART_RX_STA的Bit15位是否 為1,若是意味發送完成。
{
數據長度賦給len
for(0;t<len,t++)
{
將USART_RX_BUF[t]數組一個個通過串口1發送回數據
whilewhile(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);一直輪詢,直到當前數據發送完
}
當所有數據發送完成後,USART_RX_STA置0
}
else
列印提示內容
}
1 #include"stm32f4xx.h" 2 #include "usart.h" 3 #include "delay.h" 4 #include "sys.h" 5 6 7 int main() 8 { 9 u8 t; 10 u8 len=0; 11 u16 times; 12 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中斷優先順序分組2 13 delay_init(168); 14 uart_init(115200); 15 16 while(1) 17 { 18 19 if(USART_RX_STA&0x8000) 20 { 21 printf("\r\n您列印的消息為:\r\n"); 22 len = USART_RX_STA&0x3fff; //接收到此次接收到的數據長度 23 for(t=0;t<len;t++) 24 { 25 USART_SendData(USART1,USART_RX_BUF[t]); //將單片機接收到的數據發送回電腦 26 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); //獲取發送的狀態,輪詢直到這一條數據發送成功 27 } 28 printf("\r\n\r\n"); //插入換行 29 USART_RX_STA =0; 30 } 31 else 32 { 33 times++; 34 if(times%5000==0) 35 { 36 printf("\r\nALIENTEK 探索者STM32F407開發板 串口實驗\r\n"); 37 38 } 39 if(times%200==0)printf("請輸入數據,以回車鍵結束\r\n"); 40 delay_ms(10); 41 } 42 } 43 }
其中
USART_GetFlagStatus(main.c用到)和USART_GetITStatus(usart.c用到),敲代碼容易弄混,
USART_GetFlagStatus是在沒有使能相應的中斷函數時,通常使用該函數來判斷標誌位是否置位。
USART_GetITStatus則相反,參考關於STM32的USART_GetFlagStatus和USART_GetITStatus解析(非同步通信) - CSDN博客