USART串口协议
通信接口
串口
串口通信
第一个是USB转串口模块,上面有个芯片型号是CH340,这个芯片可以把串口协议转换为USB协议,它一边是USB口,可以插在电脑上,另一边是串口的引脚,可以和支持串口的芯片接在一起,这样就可以实现串口和电脑的通信了。中间这个图是一个陀螺仪传感器的模块,可以测量角速度、加速度这些姿态参数,它左右各有四个引脚,一边是串口的引脚,一边是I2C的引脚。右边这个图是蓝牙串口模块,下面四个引脚是串口通信的引脚,上面的芯片可以和手机互联,实现手机遥控单片机的功能。
硬件电路
电平标准
串口参数及时序
数据位有两种表示方法:一种是将校验位作为数据位的一部分,数据位为9位;另一种是将数据位和校验位独立开,数据位就是有效载荷。
串口时序
USART外设
USART简介
USART框图
接口通过三个引脚与其他设备连接在一起(见图248)。任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
● 总线在发送或接收前应处于空闲状态
● 一个起始位
● 一个数据字(8或9位),最低有效位在前
● 0.5,1.5,2个的停止位,由此表明数据帧的结束
● 使用分数波特率发生器 —— 12位整数和4位小数的表示方法。
● 一个状态寄存器(USART_SR)
● 数据寄存器(USART_DR)
● 一个波特率寄存器(USART_BRR),12位的整数和4位小数
● 一个智能卡模式下的保护时间寄存器(USART_GTPR)
关于以上寄存器中每个位的具体定义,请参考寄存器描述第25.6节:USART寄存器描述。
在同步模式中需要下列引脚:
● CK:发送器时钟输出。此引脚输出用于同步传输的 时钟, (在Start位和Stop位上没有时钟脉冲,软件可选地,可以在最后一个数据位送出一个时钟脉冲)。数据可以在RX上同步被接收。这可以用来控制带有移位寄存器的外部设备(例如LCD驱动器)。时钟相位和极性都是软件可编程的。在智能卡模式里,CK可以为智能卡提供时钟。
在IrDA模式里需要下列引脚:
● IrDA_RDI: IrDA模式下的数据输入。
● IrDA_TDO: IrDA模式下的数据输出。
下列引脚在硬件流控模式中需要:
● nCTS: 清除发送,若是高电平,在当前数据传输结束时阻断下一次的数据发送。
● nRTS: 发送请求,若是低电平,表明USART准备好接收数据
USART基本结构
数据帧
字长可以通过编程USART_CR1寄存器中的M位,选择成8或9位(见图249)。在起始位期间,TX脚处于低电平,在停止位期间处于高电平。
空闲符号被视为完全由’1’组成的一个完整的数据帧,后面跟着包含了数据的下一帧的开始位(‘1’的位数也包括了停止位的位数)。
断开符号 被视为在一个帧周期内全部收到’0’(包括停止位期间,也是’0’)。在断开帧结束时,发送器再插入1或2个停止位(‘1’)来应答起始位。
发送和接收由一共用的波特率发生器驱动,当发送器和接收器的使能位分别置位时,分别为其产生时钟。
发送器根据M位的状态发送8位或9位的数据字。当发送使能位(TE)被设置时,发送移位寄存器中的数据在TX脚上输出,相应的时钟脉冲在CK脚上输出。
字符发送
在USART发送期间,在TX引脚上首先移出数据的最低有效位。在此模式里,USART_DR寄存器包含了一个内部总线和发送移位寄存器之间的缓冲器(见图248)。
每个字符之前都有一个低电平的起始位;之后跟着的停止位,其数目可配置。USART支持多种停止位的配置:0.5、1、1.5和2个停止位。
注: 1.在数据传输期间不能复位TE位,否则将破坏TX脚上的数据,因为波特率计数器停止计数。
正在传输的当前数据将丢失。
2. TE位被激活后将发送一个空闲帧。
可配置的停止位
随每个字符发送的停止位的位数可以通过控制寄存器2的位13、12进行编程。
- 1个停止位:停止位位数的默认值。
- 2个停止位:可用于常规USART模式、单线模式以及调制解调器模式。
- 0.5个停止位:在智能卡模式下接收数据时使用。
- 1.5个停止位:在智能卡模式下发送和接收数据时使用。
空闲帧包括了停止位。
断开帧是10位低电平,后跟停止位(当m=0时);或者11位低电平,后跟停止位(m=1时)。不可能传输更长的断开帧(长度大于10或者11位)。
起始位侦测
USART可以根据USART_CR1的M位接收8位或9位的数据字。
起始位侦测
在USART中,如果辨认出一个特殊的采样序列,那么就认为侦测到一个起始位。
该序列为:1 1 1 0 X 0 X 0 X 0 0 0 0
字符接收
在USART接收期间,数据的最低有效位首先从RX脚移进。在此模式里,USART_DR寄存器包含的缓冲器位于内部总线和接收移位寄存器之间。
配置步骤:
- 将USART_CR1寄存器的UE置1来激活USART。
- 编程USART_CR1的M位定义字长
- 在USART_CR2中编写停止位的个数
- 如果需多缓冲器通信,选择USART_CR3中的DMA使能位(DMAR)。按多缓冲器通信所要求的配置DMA寄存器。
- 利用波特率寄存器USART_BRR选择希望的波特率。
- 设置USART_CR1的RE位。激活接收器,使它开始寻找起始位。
当一字符被接收到时,
● RXNE位被置位。它表明移位寄存器的内容被转移到RDR。换句话说,数据已经被接收并且
可以被读出(包括与之有关的错误标志)。
● 如果RXNEIE位被设置,产生中断。
● 在接收期间如果检测到帧错误,噪音或溢出错误,错误标志将被置起,
● 在多缓冲器通信时,RXNE在每个字节接收后被置起,并由DMA对数据寄存器的读操作而清零。
● 在单缓冲器模式里,由软件读USART_DR寄存器完成对RXNE位清除。RXNE标志也可以通过对它写0来清除。RXNE位必须在下一字符接收结束前被清零,以避免溢出错误。
注意: 在接收数据时,RE位不应该被复位。如果RE位在接收时被清零,当前字节的接收被丢失。
断开符号
当接收到一个断开帧时,USART像处理帧错误一样处理它。
空闲符号
当一空闲帧被检测到时,其处理步骤和接收到普通数据帧一样,但如果IDLEIE位被设置将产生一个中断。
溢出错误
如果RXNE还没有被复位,又接收到一个字符,则发生溢出错误。数据只有当RXNE位被清零后才能从移位寄存器转移到RDR寄存器。RXNE标记是接收到每个字节后被置位的。如果下一个数据已被收到或先前DMA请求还没被服务时,RXNE标志仍是置起的,溢出错误产生。
当溢出错误产生时:
● ORE位被置位。
● RDR内容将不会丢失。读USART_DR寄存器仍能得到先前的数据。
● 移位寄存器中以前的内容将被覆盖。随后接收到的数据都将丢失。
● 如果RXNEIE位被设置或EIE和DMAR位都被设置,中断产生。
● 顺序执行对USART_SR和USART_DR寄存器的读操作,可复位ORE位
注意: 当ORE位置位时,表明至少有1个数据已经丢失。有两种可能性:
● 如果RXNE=1,上一个有效数据还在接收寄存器RDR上,可以被读出。
● 如果RXNE=0,这意味着上一个有效数据已经被读走,RDR已经没有东西可读。当上一个
有效数据在RDR中被读取的同时又接收到新的(也就是丢失的)数据时,此种情况可能发生。在读序列期间(在USART_SR寄存器读访问和USART_DR读访问之间)接收到新的数据,此种情况也可能发生。
噪音错误
使用过采样技术(同步模式除外),通过区别有效输入数据和噪音来进行数据恢复。
当在接收帧中检测到噪音时:
● 在RXNE位的上升沿设置NE标志。
● 无效数据从移位寄存器传送到USART_DR寄存器。
● 在单个字节通信情况下,没有中断产生。然而,因为NE标志位和RXNE标志位是同时被设置,RXNE将产生中断。在多缓冲器通信情况下,如果已经设置了USART_CR3寄存器中EIE位,将产生一个中断。先读出USART_SR,再读出USART_DR寄存器,将清除NE标志位
帧错误
当以下情况发生时检测到帧错误:
由于没有同步上或大量噪音的原因,停止位没有在预期的时间上接和收识别出来。
当帧错误被检测到时:
● FE位被硬件置起
● 无效数据从移位寄存器传送到USART_DR寄存器。
● 在单字节通信时,没有中断产生。然而,这个位和RXNE位同时置起,后者将产生中断。在多缓冲器通信情况下,如果USART_CR3寄存器中EIE位被置位的话,将产生中断。顺序执行对USART_SR和USART_DR寄存器的读操作,可复位FE位。
接收期间的可配置的停止位
被接收的停止位的个数可以通过控制寄存器2的控制位来配置,在正常模式时,可以是1或2个,在智能卡模式里可能是0.5或1.5个。
- 0.5个停止位(智能卡模式中的接收):不对0.5个停止位进行采样。因此,如果选择0.5个停止位则不能检测帧错误和断开帧。
- 1个停止位:对1个停止位的采样在第8,第9和第10采样点上进行。
- 1.5个停止位(智能卡模式):当以智能卡模式发送时,器件必须检查数据是否被正确的发送出去。所以接收器功能块必须被激活(USART_CR1寄存器中的RE =1),并且在停止位的发送期间采样数据线上的信号。如果出现校验错误,智能卡会在发送方采样NACK信号时,即总线上停止位对应的时间内时,拉低数据线,以此表示出现了帧错误。FE在1.5个停止位结束时和RXNE一起被置起。对1.5个停止位的采样是在第16,第17和第18采样点进行的。1.5个的停止位可以被分成2部分:一个是0.5个时钟周期,期间不做任何事情 。随后是1个时钟周期的停止位,在这段时间的中点处采样。详见第25.3.11节:智能卡。
- 2个停止位:对2个停止位的采样是在第一停止位的第8,第9和第10个采样点完成的。如果第一个停止位期间检测到一个帧错误,帧错误标志将被设置。第二个停止位不再检查帧错误。在第一个停止位结束时RXNE标志将被设置。
波特率发生器
CH340G模块原理图
数据模式
串口发送
第一步:新建工程
第二步:连接线路
第三步:编写程序
使用printf函数需要进行下面操作
使用Serial_Printf函数打印汉字(编码方式为UTF-8),需要进行下面操作:
或者选择编码方式为GB2312。
main.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
int main (void)
{
OLED_Init ();
Serial_Init ();
Serial_SendByte ('A');
Serial_SendByte (0x41);
uint8_t MyArray[]={0x42,0x43,0x44,0x45};
Serial_SendArray(MyArray ,4);
Serial_SendString("HelloWorld!");
Serial_SendString("HelloWorld!\r\n");
Serial_SendNumber(12345, 5);
printf("Num=%d\r\n", 666);
char String[100];
sprintf(String, "\r\nNum=%d", 666);
Serial_SendString(String);
Serial_Printf("\r\n你好,世界");
Serial_Printf("\r\nNum4=%d", 444);
Serial_Printf("\r\n");
while(1)
{
}
}
Serial.c文件
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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);
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;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
/*
USART_InitTypeDef USART_InitStructure: 这是一个结构体类型的变量,用于存储初始化参数的配置信息。
USART_InitStructure.USART_BaudRate = 9600: 设置USART的波特率为9600,即每秒传输9600个位。
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None: 禁用硬件流控制,即不使用硬件流控制功能。
USART_InitStructure.USART_Mode = USART_Mode_Tx: 设置USART的工作模式为发送模式(Tx)。
USART_InitStructure.USART_Parity = USART_Parity_No: 设置USART的奇偶校验位为无校验(None)。
USART_InitStructure.USART_StopBits = USART_StopBits_1: 设置USART的停止位为1个停止位(1表示有一个额外的停止位)。
USART_InitStructure.USART_WordLength = USART_WordLength_8b: 设置USART的数据位为8位。
最后一行代码调用了名为USART_Init的函数,并将USART1和&USART_InitStructure作为参数传递给该函数,以完成USART的初始化配置。
*/
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y --)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
Serial.h文件
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
#endif
在串口助手软件中显示实验现象。
串口发送+接收
第一步:新建工程
第二步:连接线路
第三步:编写程序
main.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
int main (void)
{
OLED_Init ();
OLED_ShowString(1, 1, "RxData:");
Serial_Init ();
while(1)
{
if (Serial_GetRxFlag() == 1)
{
RxData = Serial_GetRxData();
Serial_SendByte(RxData);
OLED_ShowHexNum(1, 8, RxData, 2);
}
}
}
Serial.c文件
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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);
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);
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;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y --)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
uint8_t Serial_GetRxFlag(void)
{
if (Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
uint8_t Serial_GetRxData(void)
{
return Serial_RxData;
}
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
Serial_RxData = USART_ReceiveData(USART1);
Serial_RxFlag = 1;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
Serial.h文件
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);
#endif
USART串口数据包
HEX数据包
HEX数据包是一种二进制数据包,用于在计算机网络中传输数据。在STM32中,可以使用串口发送和接收HEX数据包。以下是一些关于如何配置HEX数据包的信息:
- 发送模式和接收模式都选择HEX模式。
- HEX数据包以FF开头,以FE结尾,是固定格式。
- 发送区的开头和结尾都是0xFF或0xFE。
- 发送区的数据由16进制表示,每个字节之间用空格分隔。
- 接收区的数据也是由16进制表示,每个字节之间用0xFF填充。
文本数据包
文本数据包是一种二进制数据包,用于在计算机网络中传输文本信息。在串口通信中,可以使用文本数据包来发送和接收文本信息。以下是一些关于如何配置文本数据包的信息:
- 文本数据包格式:可变包长、含包头包尾、包头@、载荷数据字节不固定、包尾
- 包头:用于标识文本数据包的开始和结束位置,通常包含一些控制信息,如波特率、数据位、停止位等。
- 载荷数据:实际要传输的文本信息。
- 包尾:用于标识文本数据包的结束位置。
HEX数据包接收
文本数据包接收
串口收发HEX数据包
第一步:新建工程
第二步:连接线路
第三步:编写程序
实验现象:按下按键,串口助手的接收区显示FF 01 02 03 04 EE,OLED屏上第二行显示01 02 03 04,每按一次,数据加一;在发送区输入FF FE FF 88 FE FE或FF 11 22 33 44 FE等类型的数据包,在OLED屏上第四行显示 FE FF 88 FE或11 22 33 44等数据。
main.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Key.h"
uint8_t KeyNum;
int main (void)
{
OLED_Init ();
Key_Init ();
Serial_Init ();
OLED_ShowString (1,1,"TxPacket");
OLED_ShowString (3,1,"RxPacket");
Serial_TxPacket[0]=0x01;
Serial_TxPacket[1]=0x02;
Serial_TxPacket[2]=0x03;
Serial_TxPacket[3]=0x04;
while(1)
{
KeyNum =Key_GetNum ();
if (KeyNum == 1)
{
Serial_TxPacket[0] ++;
Serial_TxPacket[1] ++;
Serial_TxPacket[2] ++;
Serial_TxPacket[3] ++;
Serial_SendPacket ();
OLED_ShowHexNum (2,1,Serial_TxPacket [0],2);
OLED_ShowHexNum (2,4,Serial_TxPacket [1],2);
OLED_ShowHexNum (2,7,Serial_TxPacket [2],2);
OLED_ShowHexNum (2,10,Serial_TxPacket [3],2);
}
if (Serial_GetRxFlag () == 1)
{
OLED_ShowHexNum (4,1,Serial_RxPacket [0],2);
OLED_ShowHexNum (4,4,Serial_RxPacket [1],2);
OLED_ShowHexNum (4,7,Serial_RxPacket [2],2);
OLED_ShowHexNum (4,10,Serial_RxPacket [3],2);
}
}
}
Serial.c文件
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxPacket[4];
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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);
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);
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;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y --)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
void Serial_SendPacket(void)
{
Serial_SendByte (0xFF);
Serial_SendArray (Serial_TxPacket ,4);
Serial_SendByte (0xEE);
}
uint8_t Serial_GetRxFlag(void)
{
if (Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t pRxPacket = 0;
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
uint8_t RxData = USART_ReceiveData (USART1 );
if(RxState == 0)
{
if (RxData == 0xFF)
{
RxState=1;
pRxPacket = 0;
}
}
else if (RxState == 1)
{
Serial_RxPacket [pRxPacket]=RxData ;
pRxPacket ++;
if (pRxPacket>=4)
{
RxState =2;
}
}
else if (RxState == 2)
{
if (RxData == 0xFE)
{
RxState = 0;
Serial_RxFlag = 1;
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
Serial.h文件
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
extern uint8_t Serial_TxPacket[];
extern uint8_t Serial_RxPacket[];
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
void Serial_SendPacket(void);
uint8_t Serial_GetRxFlag(void);
#endif
串口收发文本数据包
第一步:新建工程
第二步:连接线路
第三步:编写程序
实验现象:在串口助手的发送区输入@darea12342‘Enter’,在OLED显示屏的第四行显示darea12342。若发送LED_ON,则LED1点亮,返回接收区LED_ON_OK;若发送LED_OFF,则LED1熄灭,返回接收区LED_OFF_OK;若发送其他内容,返回接收区ERROR_COMMAND。
main.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include <string.h>
int main (void)
{
OLED_Init ();
LED_Init ();
Serial_Init ();
OLED_ShowString (1,1,"TxPacket");
OLED_ShowString (3,1,"RxPacket");
while(1)
{
if (Serial_RxFlag == 1)
{
OLED_ShowString (4,1," " );
OLED_ShowString (4,1,Serial_RxPacket );
if (strcmp (Serial_RxPacket ,"LED_ON") ==0)
{
LED1_ON ();
Serial_SendString ("LED_ON_OK\r\n");
OLED_ShowString (2,1," " );
OLED_ShowString (2,1,"LED_ON_OK" );
}
else if (strcmp (Serial_RxPacket ,"LED_OFF") ==0)
{
LED1_OFF ();
Serial_SendString ("LED_OFF_OK\r\n");
OLED_ShowString (2,1," " );
OLED_ShowString (2,1,"LED_OFF_OK" );
}
else
{
Serial_SendString ("ERROR_COMMAND\r\n");
OLED_ShowString (2,1," " );
OLED_ShowString (2,1,"ERROR_COMMAND" );
}
Serial_RxFlag = 0;
}
}
}
Serial.c文件
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
char Serial_RxPacket[100];
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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);
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);
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;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y --)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t pRxPacket = 0;
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
uint8_t RxData = USART_ReceiveData (USART1 );
if(RxState == 0)
{
if (RxData == '@' && Serial_RxFlag == 0)
{
RxState=1;
pRxPacket = 0;
}
}
else if (RxState == 1)
{
if (RxData == '\r')
{
RxState = 2;
}
else
{
Serial_RxPacket [pRxPacket ]=RxData ;
pRxPacket ++;
}
}
else if (RxState == 2)
{
if (RxData == '\n')
{
RxState = 0;
Serial_RxPacket [pRxPacket ]= '\0';
Serial_RxFlag = 1;
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
Serial.h文件
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
extern char Serial_RxPacket[];
extern uint8_t Serial_RxFlag;
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
#endif