串口配置的一般步驟
- 串口時鐘使能,GPIO時鐘使能:RCC_APB2PeriphClockCmd();
- 串口復位:USART_DeInit(); 這一步不是必須的
- GPIO端口模式設置:GPIO_Init(); 模式設置爲GPIO_Mode_AF_PP
- 串口參數初始化:USART_Init();
- 開啓中斷並且初始化NVIC(如果需要開啓中斷才需要這個步驟)
NVIC_Init();
USART_ITConfig(); - 使能串口:USART_Cmd();
- 編寫中斷處理函數:USARTx_IRQHandler();
- 串口數據收發:
void USART_SendData(); //發送數據到串口,DR
uint16_t USART_ReceiveData(); //接受數據,從DR讀取接受到的數據 - 串口傳輸狀態獲取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
注:使用中斷需要操作5、7、8步驟,否則不需要。
部分官方庫函數的解讀在該博客內有說明
https://blog.csdn.net/DX5618258/article/details/95999557
串口整體初始化函數(非庫函數/整合上述步驟1-6)
#define USART_WordLength_8b ((uint16_t)0x0000)
#define USART_StopBits_1 ((uint16_t)0x0000)
#define USART_Parity_No ((uint16_t)0x0000)
#define USART_HardwareFlowControl_None ((uint16_t)0x0000)
#define USART_Mode_Rx ((uint16_t)0x0004)
#define USART_Mode_Tx ((uint16_t)0x0008)
void uart_init(u32 bound) //串口整體初始化函數
{
//各種結構體聲明
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//使能USART1,GPIO時鐘 對應上述步驟1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//初始化USART1_TX端口對應的GPIOA9 對應上述步驟3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //設置GPIO端口號爲PA9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //設置傳輸速度爲50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //輸出模式爲複用推輓輸出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA9
//初始化USART1_RX端口對應的GPIOA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //設置GPIO端口號爲PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //輸入模式爲浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA10
//串口初始化設置 對應上述步驟4
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); //初始化串口1,該函數的部分內容在上一篇
//串口中斷設置 對應上述步驟5
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //選定串口1的中斷通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //搶佔優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的參數初始化VIC寄存器
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啓串口接收中斷
//使能串口1 對應上述步驟6
USART_Cmd(USART1, ENABLE); //該函數在上文已說明
}
串口中斷服務函數
//頭文件的定義
#define USART_REC_LEN 200 //定義最大接收字節數爲200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大USART_REC_LEN個字節,末尾爲換行符
extern u16 USART_RX_STA; //接收狀態標記
void uart_init(u32 bound);
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus; //枚舉變量
#define USART_IT_RXNE ((uint16_t)0x0525) //10100100101
//源文件的定義
#if EN_USART1_RX //如果使能了接收
u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大USART_REC_LEN個字節
u16 USART_RX_STA=0; //接收狀態標記 bit15 接收完成標誌,接收完成後爲1;
接上一行bit14 接收到0x0d後爲1;bit13-bit0 爲接收到的有效字節數
//串口中斷服務函數 對應上述步驟7
void USART1_IRQHandler(void)
{
u8 Res;
//接收中斷(接收到的數據必須是0x0d 0x0a結尾)
//獲取串口1的當前狀態,如果不等於0,則滿足條件
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1); //讀取接收到的數據(按字節接收)
//接收狀態標記(初始爲0)和0x8000進行與運算,若位15不爲0,則滿足條件
if((USART_RX_STA&0x8000)==0) //正在接收(未完成接收)
{
//接收狀態標記變量和0x4000進行與運算,若位14不爲0,則滿足條件
if(USART_RX_STA&0x4000) //上一次接收已經接收到了0x0d
{
//如果當前接收到的字節不是0x0a,則接收錯誤,接收狀態標記清零
if(Res!=0x0a)USART_RX_STA=0; //接收錯誤,重新開始
//如果當前字節是0x0a,則設置USART_RX_STA變量的位15爲1
else USART_RX_STA|=0x8000; //接收完成
}
else //上一次接收還沒有收到0x0d
{
//如果該次接收收到了0x0d,設置接收狀態標記的位14爲1
if(Res==0x0d)USART_RX_STA|=0x4000;
else //該次接收還沒收到0x0d
{
//USART_RX_BUF數組的第 位爲接收的字符(存入緩衝區)
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++; //接收次數自增(字符數+1)
//如果接收的字符數超過最大字符數-1個
if(USART_RX_STA>(USART_REC_LEN-1))
{
USART_RX_STA=0; //接收數據錯誤,重新開始接收
}
}
}
}
}
}
串口收發函數(上述函數的應用主函數)
int main(void) //串口收發函數 對應上述步驟8
{
u8 t; u8 len; u16 times=0;
//初始化延時、中斷、串口、LED
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置中斷優先級分組
uart_init(9600); //串口初始化爲9600
LED_Init(); //初始化與LED連接的硬件接口
while(1)
{
//接收狀態標記變量和0x8000進行與運算,若位15爲1(接收完成)則進入
if(USART_RX_STA&0x8000)
{
//接收狀態標記變量與0x3fff進行與運算,獲取位13-0存儲的數據長度
len=USART_RX_STA&0x3fff;
printf("\r\n您發送的消息爲:\r\n"); //打印到串口
for(t=0;t<len;t++)
{
//將DR=USART_RX_BUF中存儲的數據按位傳輸給DR寄存器
USART1->DR=USART_RX_BUF[t];
//等待SR寄存器的位6爲1時(發送完成時),跳出循環
while((USART1->SR&0X40)==0); //等待發送結束
}
printf("\r\n\r\n"); //插入換行
USART_RX_STA=0; //清空接收狀態標記變量
}
else //接收未完成
{
times++; //時間自增
if(times%5000==0) //每5000次輸出一次
{
printf("\r\n串口實驗\r\n ");
}
if(times%200==0) //每200次輸出一次
{
printf("請輸入數據,以回車鍵結束\r\n");
}
if(times%30==0)LED0=!LED0; //每30次閃爍LED一次,提示系統正在運行
delay_ms(10);
}
}
}
文中函數和部分內容摘自正點原子stm32資料與官方庫函數
自學新手,個人總結,如有出入,請多指教!