目录
- 一、串口通讯概述
- 1、广义的串口
- 2、狭义的串口
- 3、串口数据定义
- 4、串口通讯应用
- 二、STM32串口工程标准库实现
- 1、串口的初始化
- 2、串口数据发送.
- 3、串口的数据接收
一、串口通讯概述
1、广义的串口
广义的串口是针对并口来说的。串口是指设备之间通过一根数据信号线按数据位形式一位一位地传输数据的通讯端口,同一时刻只能传输一位(bit)数据。并口则是指用多条数据线进行传输的通讯方式,可以同一时刻并排传输多个数据位的数据端口。
2、狭义的串口
狭义的串口我们就特指COM口,或者称做UART口。硬件上常用的两大电压标准有TTL(只有正电压)和RS232标准(有正负电压),STM32单片机上基本都使用的TTL标准,判别电压为基准供电电压的一半。我们看到的单片机上的串口一般分为两种,一种叫USART,通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter),另一种为UART,通用异步收发器(Universal Asynchronous Receiver and Transmitter),唯一的区别很明显,就是有和没有同步通讯方式。通常硬件至少要有一对Tx和Rx加上一个GND地,有了这三个引脚就可以工作了,其它同步引脚等其它引脚可以不使用。
3、串口数据定义
完整的侦结构见下图,从一个起始位开始,接着是着多位有效数据,一般常规定义为8位,后面的就效验位,为可以选,最后一个就是停止标志位,也就是说8位有效数据的时候一个完整的帧结构就需要10位。
波特率是描述串口通讯的速度指标,有很多种,双方约定好就可以正常通讯,我们常用的有9600、115200、921600,定位bps,位每秒。
4、串口通讯应用
串口是我们使用的最基础的通信方式之一,因为引脚少,连接方便,它经常用来打印log,或作为短距离较少数据的通信方式,也可以替代I2C等偏低速通信方式。
二、STM32串口工程标准库实现
1、串口的初始化
在STM32工程main的最开始,大while()循环之前,我们的各种外设都需要初始化,如下面串口的初始化代码, 它是用来驱动串口的初始化函数uart1_init(),输入参数为波特率baud_rate,从注释中可以看到,初始化要进行以下操作步骤:
1、使能时钟;
2、自动复用的引脚,
3、配置引脚的初始化状态方式;
4、配置串口的通信属性;
5、使能串口;
6、初始化嵌套向量中断控制器中的相关中断参数,为接收做准备。
void uart1_init(u32 baud_rate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baud_rate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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);
USART_Cmd(USART1, ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
2、串口数据发送.
(1) 代码实现发送给串口1较为简单,一句话搞定:
Usart_SendString( USART1, send_data);
- 参数USART1为串口的名称,它对应着外设的内存地址映射。
- 参数send_data则是我们要发送的字符串数据,或者说是字符串指针。
(2) 重定向printf()到USART1:
- 重定向打印输出到串口1,需要定义fputc(),将打印数据的状态寄存器和数据寄存器映射到串口1,这样串口1就是打印数据口了。
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
USART_SendData(pUSARTx,ch);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);
USART1->DR = (u8) ch;
return ch;
}
3、串口的数据接收
因为单片机串口接收是一个字节一个的接收的,接收到一个字节就会进入到中断服务函数中。我们可以在中断中进行字节判断,如下面的代码实例,也可以接收一段字符后做字符串匹配判断。这里需要注意几点:
- 中断服务程序的命名是有严格要求的,请注意不要写错,否者写错了也不给报错,很难找到问题原因。
- 中断服务程序中运行的时间越短越好,也就是说代码,尽量少做判断越精简越好。
u16 num1 = 0;
char USART_RX1_BUF[HOST_REC_LEN];
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
{
USART_RX1_BUF[num1] = (uint8_t)USART_ReceiveData(USART1);
if(num1 > 2 && USART_RX1_BUF[num1-1] == '\r' && USART_RX1_BUF[num1] == '\n')
{
USART_RX1_BUF[num1+1]='\0';
SetUARTFlag(1);
num1 = 0;
return;
}
else if(num1 >= LimitSize_1)
{
USART_RX1_BUF[num1]=0x0d;
USART_RX1_BUF[num1+1]=0x0a;
USART_RX1_BUF[num1+2]='\0';
SetUARTFlag(1);
num1 = 0;
}
else
{
if(USART_RX1_BUF[0]!=0)
num1 ++;
else
num1 = 0;
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)