串口在嵌入式开发时有很多重要,常见的有:数据传输、开发测试、模块数据传递.......,本文将以数据传输和开发测试作为背景进行最精简的介绍,从串口的本质、参数、实现、现象等方面进行讲解。
串口通信
全双工,通过两根线接收或发送数据,一位一位传输,常见的标准有Uart、RS232(高低电平判定标准不同)。发送的所有数据本质上都是二进制,常用十六进制标识,对应的字母和字符按照不同的编码规则映射,发送发和接收方需要统一编码规则,eg:UTF-8、GB等。
本质是一种通信协议,可以当作约定俗称的一套规则,只不过制定他的人很权威,所以学习的时候不要畏惧。
Uart
串口通信的一种,异步通信,不需要统一的共享时钟,但通信需保证通信参数相同。
参数
波特率:一秒钟传输的码元个数,在通常情况下,一个码元代表一位也就是一个电平
校验位:无检验、奇偶检验
起始位:默认为高电平,产生一个低电位表示开始传输、一般为一位
停止位:产生一个高电平,通常为一位
数据位:传输的数据位的长度,通常为8位,每一个类型位都是独立
数据帧:封装以上比特位为一个数据帧
步骤
1.初始化时钟--GPIO、Uart
2.配置GPIO
3.配置Uart
4.使串口中断使能
5.配置NVIC,有中断必须配置
6.开启Uart
注意:只需接收二端按照约定好的进行设置,通过调用库函数,只需关心数据位
代码实现:
初始化是必须的,在接收数据的实现有区别,可以使用轮询和中断二种方式,本文采用的时中断,使用中断的话需要对串口中断和NVIC进行配置,且对串口中断的服务函数进行修改(函数名是固定的,在对应的文件里面找)。
1.初始化
void Serial_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA9引脚初始化为复用推挽输出
/*USART初始化*/
USART_InitTypeDef USART_InitStructure; //定义结构体变量
USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制,不需要
USART_InitStructure.USART_Mode = USART_Mode_Tx; //模式,选择为发送模式
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验,不需要
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位,选择1位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长,选择8位
USART_Init(USART1, &USART_InitStructure); //将结构体变量交给USART_Init,配置USART1
/*USART使能*/
USART_Cmd(USART1, ENABLE); //使能USART1,串口开始运行
}
2.发送
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte); //将字节数据写入数据寄存器,写入后USART自动生成时序波形
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成
/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}
3.接收
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断是否是USART1的接收事件触发的中断
{
Serial_RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量
Serial_RxFlag = 1; //置接收标志位变量为1
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除USART1的RXNE标志位
//读取数据寄存器会自动清除此标志位
//如果已经读取了数据寄存器,也可以不执行此代码
}
}
注意:
需要注意的主要是二个寄存器和对应的二个标志位
USART_FLAG_TXE:((Transmit Data Register Empty))
如果被置位,那么表示发送寄存器为空,即发送完毕,所以没有发送完毕就一直是RESET,while循环等待发送完毕。
USART_IT_RXNE
表示 接收寄存器非空,如果被置为SET,即有数据,进行对应接收数据的处理。
(可以从名字对它们的作用进行理解)
有关框图:
实现案例:
可以编写接收和发送的简单代码,使用串口工具进行调试,观察是否能够正确接收和发送,基本的发送和接收字节能够实现之后,所有的都是基于这个的基础上进行,只不过逻辑和实现手段要复杂一些。