STM32-串口通信学习
串口通信配置顺序
1)初始化GPIO。
2)中断和串口1配置。
3)写串口中断服务函数。
4)写主函数。
知识点梳理
1)初始化GPIO
不管是初始化GPIO口还是定时器,串口等等,都需要先进行声明。
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TX:发送数据输出引脚—对应GPIOA.9
RX:接收数据输入引脚—对应GPIOA.10
因为我们需要用到的GPIO口是PA9和10。所以我们只需要初始化这两个口。先使能串口1和GPIAOA。PA9是发送端,所以设置为复用推挽输出。PA10是接收端,设置为浮空输入模式。其速度一般设置为最大。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
2)中断和串口1配置
对中断进行分级,和使能相关通道。我觉得这些源码里面都有只有我们理解它怎么用就好。
//Usart1 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); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
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
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
3)写串口中断服务函数
这部分就是比较重要的一部分了,每当你在电脑给串口发生数据,它就会进入一次串口中断实行串口中断服务函数,这些我以学习源码为例。
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
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;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
这个中断服务函数是为了判断我们的数据是否接收成功。USART_RX_STA是判断数据是否接收成功的函数,一般用完之后要清除,这样下一个数据才能进行接收。接收到的数据都会放在数据缓存区USART_RX_BUF中,如果不清除缓存区,下一个接收的数据会覆盖原来的数据(也有可能前面的是七位字符,而后面接收的只是五位,这样子就只是覆盖了前五位,还有两位是没有覆盖的)
4)写主函数
一般我们需要使用串口实现的功能,其代码都会放在主函数中,除非使用了串口中断,并在串口中断服务函数中写了功能的相关代码。
int main(void)
{
u16 i;
u16 a=300;
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);
}
}
}
以上主函数要实现的功能为:如果我们没有发送数据,则开发板上的灯会一直闪烁,提示程序正在运行中,并在串口调试助手界面每隔一段时间打印出“请输入数据,以回车建结束”,知道我们发送了数据,例如我们发送:STM32学习资料,给单片机,系统就会先进入中断看是否接收成功,如果接收成功就回到主函数执行程序,判断接收到的数据的长度,并把数据打印到串口调试助手,使用for语句和USART_SendData函数将接收到的数据,一位一位的发回串口1中。这个大概是一个实现功能的流程,如有说得不对的请各位大佬指出。
学习小结
我也是刚刚开始学习的菜鸟,在学习这个串口通信之后呢,对于我自己的收获就是加深了一些基础知识的印象,如GPIO的初始化和配置各个参数都是比较基础的,相当重温。新知识的收获就是关于串口通信各个函数的使用,它们都有什么功能,怎么使用的,这些都了解了,也知道了如何在实现其他功能的时候加入串口通信进去一起控制程序。我觉得串口通信知识,是一个非常重要的内容,它广泛的应用到很多项目中,所以学习32的人必须要搞清楚串口通信这个知识点。分享到此,谢谢大家。