一、串口通讯协议简介:
1.串口:
串口是显控设备与信号处理板之间通信的主要接口,也是显控设备与其他设备、设备与设备之间的协议数据帧通信传输的重要接口。 串口通信指串口按位(bit)发送和接收字节。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。串口通信协议是基于串口使得通信双方能够相互沟通信息的一种约定,其定义了双方遵循的协议数据帧格式和其传输方式。 [2]在串口通信中,常用的协议包括RS-232、RS-422和RS-485。
2.电平标准:
根据通讯使用的电平标准不同,串口通讯可分为 TTL 标准及 RS-232 标准,见表 TTL 电平标准与 RS232 电平标准 。我们知道常见的电子电路中常使用 TTL 的电平标准,理想状态下,使用 5V 表示二进制逻辑 1, 使用 0V 表示逻辑 0;而为了增加串口通讯的远距离传输及抗干扰能力,它使用-15V 表示逻辑 1, +15V 表示逻辑 0。见图 RS-232 与 TTL 电平标准下表示同一个信号 。
3.RS-232 信号线:
在最初的应用中,RS-232 串口标准常用于计算机、路由与调制调解器 (MODEN,俗称“猫”) 之 间的通讯,在这种通讯系统中,设备被分为数据终端设备 DTE(计算机、路由) 和数据通讯设备 DCE(调制调解器)。我们以这种通讯模型讲解它们的信号线连接方式及各个信号线的作用。 在旧式的台式计算机中一般会有 RS-232 标准的 COM 口 (也称 DB9 接口),见图电脑主板上的 COM 口及串口线 。
其中接线口以针式引出信号线的称为公头,以孔式引出信号线的称为母头。在计算机中一般引出 公头接口,而在调制调解器设备中引出的一般为母头,使用上图中的串口线即可把它与计算机连 接起来。通讯时,串口线中传输的信号就是使用前面讲解的 RS-232 标准调制的。 在这种应用场合下,DB9 接口中的公头及母头的各个引脚的标准信号线接法见图 DB9 标准的公 头及母头接法 及表 DB9 信号线说明 。
4.数据校验:
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输 数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验 (odd)、偶校验 (even)、0 校验 (space)、1 校验 (mark) 以及无校验 (noparity),它们介绍如下: 奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为: 01101001,此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据 将是 8 位的有效数据加上 1 位的校验位总共 9 位。 偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧: 11001010,此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。 0 校验是不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为“1”。在无校验的情况下,数据包中不包含校验位。
二、功能引脚:
TX:发送数据输出引脚。
RX:接收数据输入引脚。
SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。 nRTS:请求以发送 (Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当 USART 接 收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高 电平。该引脚只适用于硬件流控制。
nCTS:清除以发送 (Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下 一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完 当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。 USART 引脚在 STM32F429IGT6 芯片具体发布见表 STM32F429IGT6 芯片的 USART 引脚 。
三、校验控制:
1.STM32F4xx 系列控制器 USART 支持奇偶校验:
当使用校验位时,串口传输的长度将是 8 位的数 据帧加上 1 位的校验位总共 9 位,此时 USART_CR1 寄存器的 M 位需要设置为 1,即 9 数据位。 将 USART_CR1 寄存器的 PCE 位置 1 就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启 动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收 数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存器的 PE 位置 1,并可以产生奇偶校 验中断。 使能了奇偶校验控制后,每个字符帧的格式将变成:起始位 + 数据帧 + 校验位 + 停止位。
2.USART 有多个中断请求事件,具体见表 USART 中断请求 :
3.硬件设计:
为利用 USART 实现开发板与电脑通信,需要用到一个 USB 转 USART 的 IC,我们选择 CH340G 芯片来实现这个功能,CH340G 是一个 USB 总线的转接芯片,实现 USB 转 USART、USB 转 IrDA 红外或者 USB 转打印机接口,我们使用其 USB 转 USART 功能。具体电路设计见图USB 转串口 硬件设计 _ 。 我们将 CH340G 的 TXD 引脚与 USART1 的 RX 引脚连接,CH340G 的 RXD 引脚与 USART1 的 TX 引脚连接。CH340G 芯片集成在开发板上,其地线 (GND) 已与控制器的 GND 连通。
四、代码呈现:
1.USART 初始化结构体:
1) USART_BaudRate:波特率设置。一般设置为 2400、9600、19200、115200。标准库函数会根据 设定值计算得到 USARTDIV 值,并设置 USART_BRR 寄存器值。
2) USART_WordLength:数据帧字长,可选 8 位或 9 位。它设定 USART_CR1 寄存器的 M 位的值。 如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位。
3) USART_StopBits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位,它设定 USART_CR2 寄存器的 STOP[1:0] 位的值,一般我们选择 1 个停止位。
4) USART_Parity:奇偶校验控制选择,可选 USART_Parity_No(无校验)、USART_Parity_Even(偶 校验) 以及 USART_Parity_Odd(奇校验),它设定 USART_CR1 寄存器的 PCE 位和 PS 位的值。
5) USART_Mode:USART 模式选择,有 USART_Mode_Rx 和 USART_Mode_Tx,允许使用逻辑或 运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位。
6) USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有 使 能 RTS、使能 CTS、同时使能 RTS 和 CTS、不使能硬件流。
2.USART 时钟初始化结构体:
1) USART_Clock:同步模式下 SCLK 引脚上时钟输出使能控制,可选禁止时钟输出 (USART_Clock_Disable) 或开启时钟输出 (USART_Clock_Enable);如果使用同步模式发送,一般都 需要开启时钟。它设定 USART_CR2 寄存器的 CLKEN 位的值。
2) USART_CPOL:同步模式下 SCLK 引脚上输出时钟极性设置,可设置在空闲时 SCLK 引脚为低 电平 (USART_CPOL_Low) 或高电平 (USART_CPOL_High)。它设定 USART_CR2 寄存器的 CPOL 位的值。
3) USART_CPHA:同步模式下 SCLK 引脚上输出时钟相位设置,可设置在时钟第一个变化沿捕 获数据 (USART_CPHA_1Edge) 或在时钟第二个变化沿捕获数据。它设定 USART_CR2 寄存器的 CPHA 位的值。USART_CPHA 与 USART_CPOL 配合使用可以获得多种模式时钟关系。
4) USART_LastBit:选择在发送最后一个数据位的时候时钟脉冲是否在 SCLK 引脚输出,可以是 不输出脉冲 (USART_LastBit_Disable)、输出脉冲 (USART_LastBit_Enable)。它设定 USART_CR2 寄 存器的 LBCL 位的值。
#include "stm32F4xx.h"
#include "stm32f4xx_conf.h"
#include "stdio.h"
#include "LED.h"
#include "key.h"
#include "delay.h"
int couter = 0;
uint8_t key1;
uint8_t key2;
uint8_t rec_data;
__IO uint32_t K1 =100000;
int8_t K2 = 0;
uint32_t system_time=0;
//通过单个字符发送,完成多个字符
//编写中断服务函数
void EXTI0_IRQHandler()
{
//是否产生了中断
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)//证明触发了中断
{
//控制灯进行颜色切换
K1=K1+10000;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI15_10_IRQHandler()
{
//是否产生了中断
if(EXTI_GetITStatus(EXTI_Line13)!=RESET)//证明触发了中断
K1-=10000;
EXTI_ClearITPendingBit(EXTI_Line13);
}
//重向定义
int fputc(int ch,FILE *p)
{
USART_SendData (USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET );
return ch;
}
void USART1_IRQHandler()
{
if(USART_GetITStatus (USART1 ,USART_IT_RXNE )!=RESET )
{
//获取接受数据
rec_data =USART_ReceiveData(USART1);
//清除中断
USART_ClearITPendingBit (USART1 ,USART_IT_RXNE );
}
}
//发送多个字节
void SendString(char *str)
{
//如果当前不等于'/0',表明字符串还没有到尾。
while(*str !='\0')
{
//发送字符串
USART_SendData (USART1,*str);
//等待当前字符发送完成
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET );
//指针指向下一个字符
str++;
}
}
int main(void)
{
//初始化串口 usart1
//pa9 pa10
GPIO_InitTypeDef gpio_info;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
LED_init();
key1_init();
key2_init();
delay_Init();
//PH0
//初始化GPIOH时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
gpio_info.GPIO_Mode = GPIO_Mode_AF;
gpio_info.GPIO_OType = GPIO_OType_PP;
gpio_info.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9;
gpio_info.GPIO_PuPd = GPIO_PuPd_UP;
gpio_info.GPIO_Speed = GPIO_Low_Speed;
GPIO_Init(GPIOA,&gpio_info);
//引脚链接到串口1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
//初始化串口外设
//1.使能串口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//2.配置串口参数
USART_InitStructure .USART_BaudRate=115200;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&USART_InitStructure);
//3.使能接收中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//4.配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
//使能串口
USART_Cmd(USART1,ENABLE);
while(1)
{
// delay_10ms(1000);
// system_time++;
// printf(" %d\r\n",system_time);
//控制LED灯
//控制其中两个灯同时亮
//第一个字节控制第一个灯,01表示开个灯
if(rec_data==0x01)
{
LED_GREEN_Ctrl(LED_OFF);
LED_RED_Ctrl(LED_ON);
LED_BLUE_Ctrl(LED_OFF);
}
else if(rec_data==0x02)
{
LED_RED_Ctrl(LED_OFF);
LED_GREEN_Ctrl(LED_ON);
}
else if(rec_data==0x03)
{
LED_RED_Ctrl(LED_OFF);
LED_GREEN_Ctrl(LED_OFF);
LED_BLUE_Ctrl(LED_ON);
}
else if(rec_data==0x04)
{
LED_RED_Ctrl(LED_ON);
LED_GREEN_Ctrl(LED_OFF);
LED_BLUE_Ctrl(LED_ON);
}
}
}