网站首页 > 技术文章 正文
串口通讯简介:
串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式。
通讯结构
设备内部一般以TTL电平传输,设备之间是通过RS232/RS485电平标准传输。
两个设备或者器件要想实现串口通讯,要电平匹配才能够正常通讯。
电平标准
根据使用的电平标准不同,串口通讯可分为 RS232标准及TTL标准,具体标准如下:
在电子电路中,模块之间常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。
协议层
1.数据包
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。
2.波特率
由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。
3.起始和停止信号
数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。
4.有效数据
有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
5.数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。
串口是我们常用的一个数据传输接口,STM32F103系列单片机共有5个串口,
其中1-3是通用同步/异步串行接口USART(Universal Synchronous/Asynchronous Receiver/Transmitter),
4、5是通用异步串行接口UART(Universal Asynchronous Receiver/Transmitter)。
STM32比51单片机好用的一个地方就是串口比较多,51单片机一般只有2个串口,有时不够用。
下面以USART1为例,说明一下STM32串口设置的一般步骤:
1) 串口时钟使能,GPIO 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
2) GPIO端口设置
设置发送和接收引脚的信息,将Tx(发送引脚)配置为推挽复用模式用来发送数据,Rx(接收引脚)配置为浮空输入模式用来接收数据。
GPIO_InitTypeDef GPIO_InitStructure;
//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
3)Usart1 NVIC 配置(如果需要开启中断,才进行本步骤的设置)
NVIC_InitTypeDef NVIC_InitStructure;
//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); //根据指定的参数初始化NVIC寄存器
//如果需要接收串口数据,则开启串口接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
4) 串口参数初始化
USART_InitTypeDef结构体,内部包含串口通讯相关工作参数:
typedef struct {
uint32_t USART_BaudRate; // 波特率
uint16_t USART_WordLength; // 字长
uint16_t USART_StopBits; // 停止位
uint16_t USART_Parity; // 校验位
uint16_t USART_Mode; // USART 模式
uint16_t USART_HardwareFlowControl; // 硬件流控制
} USART_InitTypeDef;
USART_InitTypeDef USART_InitStructure;
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) 使能串口
USART_Cmd(USART1, ENABLE); //使能串口1
6) 编写串口发送函数
//发送一个字节
void USART1_Send_Byte(u8 Data)
{
USART_GetFlagStatus(USART1, USART_FLAG_TC);
USART_SendData(USART1,Data);
while( USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET );
}
//发送字符串,遇到字符串结尾标志'\0'结束
void USART1_Send_String(u8 *Data)
{
while(*Data)
USART1_Send_Byte(*Data++);
}
//按长度发送字符串,这种方法可以发送含0x00的字符串
void USART1_Send_String_By_Lens(u8 *Data, int Len)
{
int i;
for(i=0; i<Len; i++)
{
USART_SendData(USART1, Data[i]);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); //串口1发送数据
}
}
//重定向printf函数发送字符串,一般使用此函数直接输出打印调试信息,使用方法跟C语言中的使用方法一致。
int fputc(int ch, FILE *f)
{
USART_SendData( DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return ch;
}
7) 编写中断处理函数
//串口1中断服务程序,此接收的数据是以0x0D、0x0A结尾为标志的数据帧。
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
USART_ClearFlag(USART1, USART_IT_RXNE); //清除标志位
Res =USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res==0x0D)
USART_RX_STA|=0x4000;
else 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;//接收数据错误,重新开始接收
}
}
}
}
}
接收完数据之后,在main函数中对接收到的数据进行处理。
if(USART_RX_STA&0x8000)
{
//得到此次接收到的数据长度,即USART_RX_BUF数组中的有效数据长度
uart1Len=USART_RX_STA&0x3f;
//对接收到的数据进行数据处理,接收的数据暂存在USART_RX_BUF数组中
//... ...
USART_RX_STA=0;
memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF)); //清空数组
}
串口应用:
- 与TTL串口传感器或模块直接通讯;
- 转为RS232与PC通讯;
- 转为RS485与485部件的传感器或器件通讯;
USB转串口的原理图:
使用CH340C芯片的话,就可以省略外部晶振了,可以节省PCB布局空间;
win7系统一般选择CH340作为USB转串口驱动,Win10系统下选择CH341驱动作为USB转串口驱动;
TTL串口转RS232原理图:
TTL串口转RS485原理图:
RS485总线一般使用时默认处于接收状态。
参考资料:
【正点原子】MiniSTM32开发板资料
喜欢请关注微信公众号:程序员小哈
有啥想玩的模块,留言给我,咱们一起玩
猜你喜欢
- 2024-10-12 STM32单片机-多串口printf()问题与ASCII码解析
- 2024-10-12 stm32F0 串口的几个特殊功能 stm32f1串口引脚
- 2024-10-12 STM32串口发送用哪个中断? stm32f4串口发送数据
- 2024-10-12 STM32F103编程学习——USB虚拟串口篇
- 2024-10-12 STM32F4入坑日记——串口发送数据(非中断)
- 2024-10-12 STM32 HAL库串口中断发送过程 stm32f4串口中断
- 2024-10-12 在货物监控设备研发时,STM32串口第一个字节丢失解怎么解决?
- 2024-10-12 STM32单片机采用环形缓冲区实现串口中断数据接收管理
- 2024-10-12 基于STM32的串口与DMA的完美组合(上)
- 2024-10-12 STM32下载程序新思路--使用串口下载STM32程序
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)