优化网站内容,下载的asp网页模板怎么应用到网站,做电影网站心得体会,四川铁科建设监理有限公司官方网站接口 串口通信 硬件电路 电平标准 串口参数、时序 USART USART主要框图
TXE: 判断发送寄存器是否为空 RXNE: 判断接收寄存器是否非空 RTS为输出信号#xff0c;用于表示MCU串口是否准备好接收数据#xff0c;若输出信号为低电平#xff0c;则说明MCU串口可以接收数据#…接口 串口通信 硬件电路 电平标准 串口参数、时序 USART USART主要框图
TXE: 判断发送寄存器是否为空 RXNE: 判断接收寄存器是否非空 RTS为输出信号用于表示MCU串口是否准备好接收数据若输出信号为低电平则说明MCU串口可以接收数据请求发送数据。当接收寄存器已满时RTS将被设置为高电平 CTS为输入信号用于判断MCU串口是否可以向对方发送数据若接收信号为低电平则说明MCU串口可以向对方发送数据。若为高电平则在发送当前数据帧之后停止发送
数据帧 起始位侦测及采样位置对齐
将一个数据周期分为16个采样周期取中间值作为该周期的电平
波特率发生器
DIV: 分频系数 例子求波特率为9600的分频系数960072M / 16 / DIV
CH340G 内部结构 串口接线图 数据模式 勾选Use MicroLIB , 重定向printf 封装sprintf()
sprintf函数打印到字符串中要注意字符串的长度要足够容纳打印的内容否则会出现内存溢出而printf函数打印输出到屏幕上。sprintf函数在我们完成其他数据类型转换成字符串类型的操作中应用广泛。 format为要打印的字符串格式va_list 是参数列表从format的位置开始接收参数表存进arg再将arg打印到string变量中释放arg通过串口发送string 需添加头文件 #include stdarg.h
串口输出中文防止乱码
--no-multibyte-chars
串口发送实例源码
#include stm32f10x.h // Device header
#include stdio.h
#include stdarg.h/*** 函 数串口初始化* 参 数无* 返 回 值无*/
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引脚初始化为复用推挽输出/*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_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使能*/USART_Cmd(USART1, ENABLE); //使能USART1串口开始运行
}/*** 函 数串口发送一个字节* 参 数Byte 要发送的一个字节* 返 回 值无*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位故此循环后无需清除标志位*/
}/*** 函 数串口发送一个数组* 参 数Array 要发送数组的首地址* 参 数Length 要发送数组的长度* 返 回 值无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i 0; i Length; i ) //遍历数组{Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数串口发送一个字符串* 参 数String 要发送字符串的首地址* 返 回 值无*/
void Serial_SendString(char *String)
{uint8_t i;for (i 0; String[i] ! \0; i )//遍历字符数组字符串遇到字符串结束标志位后停止{Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数次方函数内部使用* 返 回 值返回值等于X的Y次方*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result 1; //设置结果初值为1while (Y --) //执行Y次{Result * X; //将X累乘到结果}return Result;
}/*** 函 数串口发送数字* 参 数Number 要发送的数字范围0~4294967295* 参 数Length 要发送数字的长度范围0~10* 返 回 值无*/
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); //依次调用Serial_SendByte发送每位数字}
}/*** 函 数使用printf需要重定向的底层函数* 参 数保持原始格式即可无需变动* 返 回 值保持原始格式即可无需变动*/
int fputc(int ch, FILE *f)
{Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数return ch;
}/*** 函 数自己封装的prinf函数* 参 数format 格式化字符串* 参 数... 可变的参数列表* 返 回 值无*/
void Serial_Printf(char *format, ...)
{char String[100]; //定义字符数组va_list arg; //定义可变参数列表数据类型的变量argva_start(arg, format); //从format开始接收参数列表到arg变量vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中va_end(arg); //结束变量argSerial_SendString(String); //串口发送字符数组字符串
}
HEX数据包
传输速度快包头和包尾与有效数据部分可能重复
文本数据包
传输数据直观包头包尾与有效数据不会重复但解析效率低
接收HEX数据包 文本数据包接收
Hex数据包接收结果 源码
#include stm32f10x.h // Device header
#include MyDelay.h //自定义延时函数
#include Delay.h //官方延迟函数
#include Button.h //按键Led驱动
#include stdio.h
#include OLED.h
#include Button.h
#include Serial.hint main(void){//环境配置OLED_Init();Serial_Init();Button_Init();OLED_ShowString(1,1,TxData...);OLED_ShowString(3,1,RxData...); Serial_TxPacket[0] 0x01; Serial_TxPacket[1] 0x02; Serial_TxPacket[2] 0x03; Serial_TxPacket[3] 0x04; uint8_t Key_Num 0;while(1){Key_Num Key_GetNum();OLED_ShowNum(1,10,Key_Num,4);if(Key_Num 1){ //按键按下执行数据发送通过OLED展示发送的数据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,11,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,11,Serial_RxPacket[3],2);}} return 0;
}
#include stm32f10x.h //Device header
#include stdio.h
#include stdarg.h
#include Serial.h//定义串口接收的数据包和标志位
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxPacket[4];//串口初始化
void Serial_Init(void){//开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; //Pin_9推挽复用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; //Pin_10上拉输入GPIO_InitStructure.GPIO_Pin GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStructure);//USART初始化USART_InitTypeDef UI;UI.USART_BaudRate 9600;UI.USART_HardwareFlowControl USART_HardwareFlowControl_None;UI.USART_Mode USART_Mode_Tx | USART_Mode_Rx;UI.USART_Parity USART_Parity_No; //无需奇偶校验UI.USART_StopBits USART_StopBits_1;UI.USART_WordLength USART_WordLength_8b;USART_Init(USART1,UI);//USART中断输出配置USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//NVIC中断配置分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NI;NI.NVIC_IRQChannel USART1_IRQn;NI.NVIC_IRQChannelCmd ENABLE;NI.NVIC_IRQChannelPreemptionPriority 1;NI.NVIC_IRQChannelSubPriority 1; NVIC_Init(NI);//USART使能USART_Cmd(USART1,ENABLE);}/*** 函 数串口发送一个字节* 参 数Byte 要发送的一个字节* 返 回 值无*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位故此循环后无需清除标志位*/
}/*** 函 数串口发送一个数组* 参 数Array 要发送数组的首地址* 参 数Length 要发送数组的长度* 返 回 值无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i 0; i Length; i ) //遍历数组{Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数串口发送一个字符串* 参 数String 要发送字符串的首地址* 返 回 值无*/
void Serial_SendString(char *String)
{uint8_t i;for (i 0; String[i] ! \0; i )//遍历字符数组字符串遇到字符串结束标志位后停止{Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据}}/*** 函 数次方函数内部使用* 返 回 值返回值等于X的Y次方*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result 1; //设置结果初值为1while (Y --) //执行Y次{Result * X; //将X累乘到结果}return Result;
}/*** 函 数串口发送数字* 参 数Number 要发送的数字范围0~4294967295* 参 数Length 要发送数字的长度范围0~10* 返 回 值无*/
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); //依次调用Serial_SendByte发送每位数字}
}/** * 函 数使用printf需要重定向的底层函数* 参 数保持原始格式即可无需变动* 返 回 值保持原始格式即可无需变动*/
int fputc(int ch, FILE *f)
{Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数return ch;
}/*** 函 数自己封装的prinf函数* 参 数format 格式化字符串* 参 数... 可变的参数列表* 返 回 值无*/
void Serial_Printf(char *format, ...)
{char String[100]; //定义字符数组va_list arg; //定义可变参数列表数据类型的变量argva_start(arg, format); //从format开始接收参数列表到arg变量vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中va_end(arg); //结束变量argSerial_SendString(String); //串口发送字符数组字符串
}/*** 函 数获取串口接收标志位* 参 数无* 返 回 值串口接收标志位范围0~1接收到数据后标志位置1读取后标志位自动清零*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag 1) //如果标志位为1{Serial_RxFlag 0;return 1; //则返回1并自动清零标志位}return 0; //如果标志位为0则返回0
}/*** 函 数获取串口接收的数据* 参 数无* 返 回 值接收的数据范围0~255*/
uint8_t Serial_GetRxData(void)
{return Serial_RxData; //返回接收的数据变量
}/*** 函 数USART1中断函数* 参 数无* 返 回 值无* 注意事项此函数为中断函数无需调用中断触发后自动执行* 函数名为预留的指定名称可以从启动文件复制* 请确保函数名正确不能有任何差异否则中断函数将不能进入*/
void USART1_IRQHandler(void)
{//在中断函数中执行状态机转换static uint8_t RxState 0;static uint8_t nRxPacket; //接收的第n个有效数据载荷 if(USART_GetITStatus(USART1,USART_IT_RXNE) SET ){ //判断中断是否生效uint8_t RxData USART_ReceiveData(USART1);//状态机三个状态if(RxState 0){if(RxData 0xFF){RxState 1;nRxPacket 0;}} else if(RxState 1){Serial_RxPacket[nRxPacket] RxData; //接收第n个载荷数据if(nRxPacket 4 ) {RxState 2;} } else if(RxState 2){if(RxData 0xFE){ //包尾RxState 0; //接收一个数据包完成重新开始一轮状态机Serial_RxFlag 1; //置完成标志位}} USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志位 }}//发送数据包
void Serial_SendPacket(void){Serial_SendByte(0xFF); //发送包头Serial_SendArray(Serial_TxPacket, 4);Serial_SendByte(0xFE);
}
#ifndef __SERIAL_H
#define __SERIAL_H#include stdio.hextern 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接收文本数据包 点亮小灯
#include stm32f10x.h // Device header
#include MyDelay.h //自定义延时函数
#include Delay.h //官方延迟函数
#include Button.h //按键Led驱动
#include stdio.h
#include OLED.h
#include Button.h
#include Serial.hint main(void){//环境配置OLED_Init();Serial_Init();Button_Init();OLED_ShowString(1,1,TxData...);OLED_ShowString(3,1,RxData...); Serial_TxPacket[0] 0x01; Serial_TxPacket[1] 0x02; Serial_TxPacket[2] 0x03; Serial_TxPacket[3] 0x04; uint8_t Key_Num 0;while(1){if(Serial_GetRxFlag() 1){ //若接收完成一个数据包进行相应展示OLED_ShowString(4,1, ); //空白行用于被某些重复数据覆盖OLED_ShowString(4,1,Serial_RxPacket);//根据串口接收到的命令点亮小灯if(strcmp(Serial_RxPacket,LED_ON)0){LED1_ON();Serial_SendString(LED1_ON\r\n); //开灯} else if(strcmp(Serial_RxPacket,LED_OFF)0){LED1_OFF();Serial_SendString(LED1_OFF\r\n); //关灯} else {Serial_SendString(Error\r\n); //错误指令} }} return 0;
}
#include stm32f10x.h //Device header
#include stdio.h
#include stdarg.h
#include Serial.h//定义串口接收的数据包和标志位
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t Serial_TxPacket[4];
char Serial_RxPacket[100];//串口初始化
void Serial_Init(void){//开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; //Pin_9推挽复用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; //Pin_10上拉输入GPIO_InitStructure.GPIO_Pin GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStructure);//USART初始化USART_InitTypeDef UI;UI.USART_BaudRate 9600;UI.USART_HardwareFlowControl USART_HardwareFlowControl_None;UI.USART_Mode USART_Mode_Tx | USART_Mode_Rx;UI.USART_Parity USART_Parity_No; //无需奇偶校验UI.USART_StopBits USART_StopBits_1;UI.USART_WordLength USART_WordLength_8b;USART_Init(USART1,UI);//USART中断输出配置USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//NVIC中断配置分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NI;NI.NVIC_IRQChannel USART1_IRQn;NI.NVIC_IRQChannelCmd ENABLE;NI.NVIC_IRQChannelPreemptionPriority 1;NI.NVIC_IRQChannelSubPriority 1; NVIC_Init(NI);//USART使能USART_Cmd(USART1,ENABLE);}/*** 函 数串口发送一个字节* 参 数Byte 要发送的一个字节* 返 回 值无*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位故此循环后无需清除标志位*/
}/*** 函 数串口发送一个数组* 参 数Array 要发送数组的首地址* 参 数Length 要发送数组的长度* 返 回 值无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i 0; i Length; i ) //遍历数组{Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数串口发送一个字符串* 参 数String 要发送字符串的首地址* 返 回 值无*/
void Serial_SendString(char *String)
{uint8_t i;for (i 0; String[i] ! \0; i )//遍历字符数组字符串遇到字符串结束标志位后停止{Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据}}/*** 函 数次方函数内部使用* 返 回 值返回值等于X的Y次方*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result 1; //设置结果初值为1while (Y --) //执行Y次{Result * X; //将X累乘到结果}return Result;
}/*** 函 数串口发送数字* 参 数Number 要发送的数字范围0~4294967295* 参 数Length 要发送数字的长度范围0~10* 返 回 值无*/
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); //依次调用Serial_SendByte发送每位数字}
}/** * 函 数使用printf需要重定向的底层函数* 参 数保持原始格式即可无需变动* 返 回 值保持原始格式即可无需变动*/
int fputc(int ch, FILE *f)
{Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数return ch;
}/*** 函 数自己封装的prinf函数* 参 数format 格式化字符串* 参 数... 可变的参数列表* 返 回 值无*/
void Serial_Printf(char *format, ...)
{char String[100]; //定义字符数组va_list arg; //定义可变参数列表数据类型的变量argva_start(arg, format); //从format开始接收参数列表到arg变量vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中va_end(arg); //结束变量argSerial_SendString(String); //串口发送字符数组字符串
}/*** 函 数获取串口接收标志位* 参 数无* 返 回 值串口接收标志位范围0~1接收到数据后标志位置1读取后标志位自动清零*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag 1) //如果标志位为1{Serial_RxFlag 0;return 1; //则返回1并自动清零标志位}return 0; //如果标志位为0则返回0
}/*** 函 数获取串口接收的数据* 参 数无* 返 回 值接收的数据范围0~255*/
uint8_t Serial_GetRxData(void)
{return Serial_RxData; //返回接收的数据变量
}/*** 函 数USART1中断函数* 参 数无* 返 回 值无* 注意事项此函数为中断函数无需调用中断触发后自动执行* 函数名为预留的指定名称可以从启动文件复制* 请确保函数名正确不能有任何差异否则中断函数将不能进入*/
void USART1_IRQHandler(void)
{//在中断函数中执行状态机转换static uint8_t RxState 0;static uint8_t nRxPacket; //接收的第n个有效数据载荷 if(USART_GetITStatus(USART1,USART_IT_RXNE) SET ){ //判断中断是否生效uint8_t RxData USART_ReceiveData(USART1);//状态机三个状态if(RxState 0){if(RxData ){RxState 1;nRxPacket 0;}} else if(RxState 1){Serial_RxPacket[nRxPacket] RxData; //接收第n个载荷数据if(RxData \r) {RxState 2;} } else if(RxState 2){if(RxData \n){ //包尾RxState 0; //接收一个数据包完成重新开始一轮状态机Serial_RxPacket[nRxPacket] \0; //字符串结束标志位Serial_RxFlag 1; //置完成标志位}} USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志位 }}//发送数据包
void Serial_SendPacket(void){Serial_SendByte(0xFF); //发送包头Serial_SendArray(Serial_TxPacket, 4);Serial_SendByte(0xFE);
}
#ifndef __SERIAL_H
#define __SERIAL_H#include stdio.hextern uint8_t Serial_TxPacket[];
extern char 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