目录
1.什么是串口?
(1)串口,即串行通信端口,与并行接口不同之处在于,传输一个字节(8位数据)时,串口是将8个位排好队,逐个的在1条连接线上传输,而并口则将8个位一字排开,分别在8条连接线上同时传输 。
只要进行串行通讯的应该都属于串口。
2.串口通信的接口标准
(1)正常而言,常用的串口通信的接口标准有RS-232C、RS-232、RS-422A、RS-485、USB等等。RS-232-C、RS-422与RS-485标准只对接口的电气特性做出规定,不涉及接外挂程式、电缆或协议。USB是近几年发展起来的新型接口标准,主要应用于高速数据传输领域。
其中,需要注意的是以上标准只是一种电平标准,而COM口肯定使用RS-232标准,UART口一般使用TTL标准。PC机一般有两个串行口COM1和COM2。通常COM1使用的是9 针D 形连接器,也称之为RS-232接口,而COM2有的使用的是老式的DB25针连接器,也称之为RS-422接口,不过已经很少使用。
常用于电脑的标准串口RS-232的D型9针连接器
1、载波检测(CD)
2、接受数据(RXD)
3、发出数据(TXD)
4、数据终端准备好(DTR)
5、信号地线(SG)
6、数据准备好(DSR)
7、请求发送(RTS)
8、清除发送(CTS)
9、振铃指示(RI)
(2)除了标准串口RS-232代表的COM口的串口外,还分为USB口、SATA接口,对于嵌入式而言,嵌入式里面说的串口,一般是指UART口。而UART串口一般用的是TTL电平,所以就要用CH340芯片进行转换,需要注意的是RS-232与TTL只是一种电平标准,而COM口和UART口是物理接口,只是COM口肯定使用RS-232标准,而UART一般使用TTL标准,可是电脑上的USB接口的输出电压为直流5V,输出电流不大于500毫安 并且与TTL电平不兼容,所以信号传输时需要电平转换电路。
所以电脑USB通过CH430芯片输出TTL电平 给单片机 ,这便是USB转TTL
这四个,就是常用的USB转TTL串口模块。
3.基于Stm32的USART串口的使用
①USART引脚资源
在STM32里,串口通信是USART,STM32可以通过串口和其他设备进行传输并行数据,是全双工,异步时钟控制,设备之间是点对点的传输。对应的STM32引脚分别是RX和TX端。STM32的串口资源有USART1、USART2、USART3。但在最小系统版STM32F103C8T6中只有USART1和USART2串口引脚资源,如下图:
1、接受数据(RX)
2、发出数据(TX)
3、请求发送(RTS)
4、清除发送(CTS)
②串口重要参数
(1)波特率
串口通信的速率,USART_BaudRate: 波特率设置。一般设置为2400、9600、19200、115200。标准库函数会根据设定值计算得到USARTDIV值,从而设置USART_BRR寄存器值。
USART_InitStruct.USART_BaudRate=9600;
(2)硬件流控制
USART_HardwareFlowControl: 硬件流控制选择,只有在硬件流控制模式才有效,可选有⑴使能RTS、⑵使能CTS、⑶同时使能RTS和CTS、⑷不使能硬件流。一般选择第四个
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
(3)模式
USART_Mode: USART模式选择,有USART_Mode_Rx和USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定USART_CR1寄存器的RE位和TE位。此处发送模式和接收模式均选择
USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
(4)校验位
USART_Parity: 奇偶校验控制选择,可选USART_Parity_No(无校验)、USART_Parity_Even(偶校验)以及USART_Parity_Odd(奇校验),它设定USART_CR1寄存器的PCE位和PS位的值。用于数据验证,根据数据位的计算得来。奇偶校验,一般不需要
USART_InitStruct.USART_Parity=USART_Parity_No; //不选择校验
(4)停止位
USART_StopBits: 停止位设置,可选0.5个、1个、1.5个和2个停止位,它设定USART_CR2寄存器的STOP[1:0]位的值,一般我们选择1个停止位。
USART_InitStruct.USART_StopBits=USART_StopBits_1; //停止位1位
(5)数据位
USART_WordLength: 数据帧字长,可选8位或9位。它设定USART_CR1寄存器的M位的值。如果没有使能奇偶校验控制,一般使用8数据位;如果使能了奇偶校验则一般设置为9数据位。
USART_InitStruct.USART_WordLength=USART_WordLength_8b; //数据位8位
(6)配置结构体
当使用同步模式时需要配置SCLK引脚输出脉冲的属性,标准库使用一个时钟初始化结构体USART_ClockInitTypeDef来设置,该结构体内容也只有在同步模式才需要设置。
USART_InitTypeDef USART_InitStructure; //定义结构体变量
③串口函数的常规写法(江协版)
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引脚初始化为复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA10引脚初始化为上拉输入 /*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_Mode_Rx; //模式,发送模式和接收模式均选择 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_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接收数据的中断 /*NVIC中断分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2 /*NVIC配置*/ NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择配置NVIC的USART1线 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1 NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设 /*USART使能*/ USART_Cmd(USART1, ENABLE); //使能USART1,串口开始运行 }
④梳理USART串口函数写法思路
首先开启USART的RCC时钟,顺便将RX,TX所需的RCC时钟GPIO开启
之后将RX,TX所需的引脚资源进行定义,RX的Mode模式为上拉输入或浮空输入,TX的Mode模式为复用推挽输出。
然后将USART初始化,进行初步定义
最后配置串口接收中断,设置中断函数,使能USART1。
⑤接收|发送代码写法
然后就可以接收和发送了
接收代码
/**
* 函 数:获取串口接收标志位
* 参 数:无
* 返 回 值:串口接收标志位,范围:0~1,接收到数据后,标志位置1,读取后标志位自动清零
*/
uint8_t Serial_GetRxFlag(void)
{
if (Serial_RxFlag == 1) //如果标志位为1
{
Serial_RxFlag = 0;
return 1; //则返回1,并自动清零标志位
}
return 0; //如果标志位为0,则返回0
}
发送代码
/**
* 函 数:串口发送一个字节
* 参 数:Byte 要发送的一个字节
* 返 回 值:无
*/
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte); //将字节数据写入数据寄存器,写入后USART自动生成时序波形
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成
/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}
⑥最重要的标准位问题
考虑标志位的问题,如下文
USART_FLAG_TXE:
注意左上角紫色的框,以及发送数据的流程,当我们去调用函数**USART_SendData(pUSARTx,ch);的时候,一个字节的数据就会被写入发送数据寄存器(TDR),注意USART_FLAG_TXE这个标志位,不发送数据的时候,闲着的时候都是0,当检测到数据写入发送数据寄存器TDR的时候,就会立刻将USART_FLAG_TXE置1,然后数据移位寄存器(TSR)就开始从TDR寄存器中取数据,一位一位的取走发送出去,当被取完的时候,发送数据寄存器TDR也就为空了,所以此时USART_FLAG_TXE**标志位就会被置0 ,所以也是我们while检测这个标志的原因
USART_FLAG_TC:
我们来假设一个过程,当我们调用**USART_SendData(pUSARTx,ch)发送一个字节的数据的时候,此时数据移位寄存器(TSR)就会立刻从数据发送寄存器(TDR)中开始搬运数据并一位一位发送出去,但是受限于波特率,搬运的速度会远大于发送的速率,而只要搬运完了,USART_FLAG_TXE这个标志位就会立刻被置0,我们while循环检测这个标志,此时就会被唤醒,看我上面发送字符串的函数就能看出来,下一个数据立刻又被写入发送数据寄存器(TDR),然后移位数据寄存器又开始搬运了,注意注意:此时移位数据寄存器中,上一个字节的数据还不一定发送完成呢,所以会为空吗?不会,所以所以:USART_FLAG_TC**这个标志位的作用是:检测数据移位寄存器是否为空,当开始发送数据,数据移位寄存器从数据发送寄存器中搬运数据,这个标志位就会被置1,当所有数据发送完成,移位寄存器为空时,就会被置0,所以通过这个标志位,可以实现在字节流的传输方式中实现帧传输
总结:
对于嵌入式而言,串口是必不可少的一环,以上的文字是我总结我所见到的博客和我自己的一些学习心得。认真了解串口之后,才发现串口应用之广泛,我所学所写的还有很多不足。
一起前进吧各位,加油!加油!加油!