stm32单片机开发四、USART

ops/2024/10/18 19:24:04/

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述串口的空闲状态时高电平,起始位是低电平,来打破空闲状态的高电平
必须要有停止位,停止位一般为一位高电平
串口常说的数据为8N1,其实就是8个数据位(固定的),N就是none,也就是0个校验位,1个停止位
如果说有校验位,那么就会在8位数据位后加一位校验位,共9位数据,然后时1位停止位
如果使用了奇校验,那么包括校验位在内的9位数据会出现奇数个1,比如如果你传输0000 1111,目前总共4个1,是偶数个,那么校验位就需要再补一个1,连同校验位就是0000 1111 1,总共5个1,保证1为奇数,如果数据是0000 1110,此时3个1,是奇数个,那么校验位就补一个0,连同校验位就是0000 11100,总共还是3个1,1的个数为奇数。发送方,在发送数据后,会补一个校验位,保证1的个数为奇数,接收方,在接收数据后,会验证数据位和校验位,如果1的个数还是奇数,就认为数据没有出错,如果在传输中,因为干扰,有一位由1变成0,或者由0变成1了,那么整个数据的奇偶特性就会变化

在这里插入图片描述在转移的同时,置一个RXNE标志位,我们检查这个标志位,就可以知道是不是收到数据了,这个标志位也可以申请中断
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

#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);	//开启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引脚初始化为复用推挽输出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);					//将PA10引脚初始化为上拉输入/*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_Mode_Rx;	//模式,发送模式和接收模式均选择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_ITConfig(USART1, USART_IT_RXNE, ENABLE);			//开启串口接收数据的中断/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);			//配置NVIC为分组2/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure;					//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;		//选择配置NVIC的USART1线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;		//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);							//将结构体变量交给NVIC_Init,配置NVIC外设/*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);		//串口发送字符数组(字符串)
}/*** 函    数:获取串口接收标志位* 参    数:无* 返 回 值:串口接收标志位,范围: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)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)		//判断是否是USART1的接收事件触发的中断{Serial_RxData = USART_ReceiveData(USART1);				//读取数据寄存器,存放在接收的数据变量Serial_RxFlag = 1;										//置接收标志位变量为1USART_ClearITPendingBit(USART1, USART_IT_RXNE);			//清除USART1的RXNE标志位//读取数据寄存器会自动清除此标志位//如果已经读取了数据寄存器,也可以不执行此代码}
}

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初始化/*显示静态字符串*/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);	//显示串口接收的数据}}
}

http://www.ppmy.cn/ops/28168.html

相关文章

启发式搜索算法4 -遗传算法实战:吊死鬼游戏

相关文章: 启发式搜索算法1 – 最佳优先搜索算法 启发式搜索算法2 – A*算法 启发式搜索算法2 – 遗传算法 有一个小游戏叫吊死鬼游戏&#xff08;hangman&#xff09;&#xff0c;在学习英语的时候&#xff0c;大家有可能在课堂上玩过。老师给定一个英文单词&#xff0c;同学们…

MySql:连接和关闭

c connector 下面是一个示例&#xff0c;世界使用c connector时注意release版本和debug版本要和响应的动态库匹配才可以 #include <mysql_driver.h> #include <mysql_connection.h> #include <cppconn/resultset.h> #include <cppconn/statement.h>i…

k8s-实战——kubeadm安装1.30.0

文章目录 1介绍1.1软件架构1.2版本介绍1.3组件列表2操作步骤2.1环境准备2.2获取脚本2.3节点初始化2.4组件下载2.4.1脚本执行2.4.2目录组件2.5脚本修改2.5.1修改host文件2.5.2验证ansible配置2.6安装k8s集群2.6.1查看证书有效期

vulnhub靶场之FunBox-1

一.环境搭建 1.靶场描述 Boot2Root ! This is a reallife szenario, but easy going. You have to enumerate and understand the szenario to get the root-flag in round about 20min. This VM is created/tested with Virtualbox. Maybe it works with vmware. If you n…

【Go语言快速上手(六)】管道, 网络编程,反射,用法讲解

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; GO快速上手 1. 前言2. 初识管道3. 管…

类加载子系统之类的生命周期(待完善)

0、前言 文中大量图片来源于 B站 黑马程序员 0.1、类加载子系统在 JVM 中的位置 类加载器负责的事情是&#xff1a;加载、链接、解析 0.2、与类的生命周期相关的虚拟机参数 参数描述-XX:TraceClassLoading打印出加载且初始化的类 1、类的生命周期 堆上的变量在分配空间的时…

分类规则挖掘(二)

目录 三、决策树分类方法&#xff08;一&#xff09;决策树生成框架&#xff08;二&#xff09;ID3分类方法&#xff08;三&#xff09;决策树的剪枝&#xff08;四&#xff09;C4.5算法 三、决策树分类方法 决策树 (Decision Tree) 是从一组无次序、无规则&#xff0c;但有类别…

C++中lambda表达式的使用及注意事项

在C中一共有四种可调用对象&#xff0c;分别是函数&#xff0c;函数指针&#xff0c;仿函数&#xff0c;和lambda表达式&#xff0c;本文将从lambda表达式的定义形式开始&#xff0c;到lambda表达式的使用场景&#xff0c;向你讲述lambda的使用及注意事项。 lambda表达式的定义…