串口配置的一般步骤
- 串口时钟使能,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资料与官方库函数
自学新手,个人总结,如有出入,请多指教!