嵌入式软件--stm32 DAY 6 USART串口通讯(下)

1.寄存器轮询_收发字符串

通过寄存器轮询方式实现了收发单个字节之后,我们趁热打铁,争上游,进阶到字符串。字符串就是多个字符。很明显可以循环收发单个字节实现。

然后就是接收字符串。如果接受单个字符的函数放在while里,它也可以实现一个一个的接收字符串,在一定时间戳下,效果等同。

然后我们要想想如何整合,写成一个函数。

2.问题解答,状态位清零

我们的编程方式,一个是寄存器写法,一个是hal库写法。还有的就是实现思路。

复制代码
//发送一个字符
void USART_SendChar(uint8_t ch)
{
   //判断TDR是否为空,必须等待TDR为空才能写入数据,也就是继续发送
   while((USART1->SR & USART_SR_TXE)==0)
   {

   }

   //将要发送的数据写入TDR
   USART1->DR = ch;
}

初始的时候,TDR的存储寄存器肯定为空

关于状态位清零,TXE和RXNE都可以自动清零。

只要发数据,就自动清零。

RXNE也是一样,只要读RDR,就会清零。

3.串口通讯 寄存器中断方式

复制上一个工程文件,把改删除的删掉。

主要配置中断管理NVIC

中断服务函数

main.c

cpp 复制代码
#include "usart.h"
#include "delay.h"
#include <string.h>
//定义接收缓冲区和接收数据长度
uint8_t buff[100];
uint8_t size;
int main(void)
{
	//1.初始化
    USART_Init();
	
	//发送单个字符
	USART_SendChar('A');
	USART_SendChar('\n');
	//发送字符串
	uint8_t str[]="Hello World!\n";
	USART_SendString(str,strlen((char *)str));
	while(1)
	{
		
	}
	
}

usart.c

cpp 复制代码
#include "usart.h"

//初始化
void USART_Init(void)
{
   //开启时钟
   RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
   RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

   //GPIO工作模式
   // PA9:TX 复用推挽输出,CNF=10,MODE=11
   GPIOA->CRH |= GPIO_CRH_MODE9;
   GPIOA->CRH |= GPIO_CRH_CNF9_1;
   GPIOA->CRH &= ~GPIO_CRH_CNF9_0;
   // PA10:RX 浮空输入,CNF=01,MODE=00
   GPIOA->CRH &= ~GPIO_CRH_MODE10;
   GPIOA->CRH &= ~GPIO_CRH_CNF10_1;
   GPIOA->CRH |= GPIO_CRH_CNF10_0;
   
   //串口模块设置
   //设置波特率 115200
   USART1->BRR = 0x271;
   //使能串口和收发模块
   USART1->CR1 |= USART_CR1_UE;
   USART1->CR1 |= (USART_CR1_TE|USART_CR1_RE);
   
   //配置数据帧格式
   USART1->CR1 &=~ USART_CR1_M;   //长度为8位的数据,没有校验位
   USART1->CR1 &=~ USART_CR1_PCE;  //无校验,不使用校验位
   USART1->CR2 &=~ USART_CR2_STOP;  //1位停止位

   //使能串口接收中断
   USART1->CR1 |= USART_CR1_RXNEIE;
   USART1->CR1 |= USART_CR1_IDLEIE;

   //配置NVIC
   NVIC_SetPriorityGrouping(3);
   NVIC_SetPriority (USART1_IRQn,2);
   NVIC_EnableIRQ(USART1_IRQn);
   }

//发送一个字符
void USART_SendChar(uint8_t ch)
{
   //判断TDR是否为空,必须等待TDR为空才能写入数据,也就是继续发送
   while((USART1->SR & USART_SR_TXE)==0)
   {

   }

   //将要发送的数据写入TDR
   USART1->DR = ch;
}



//发送字符串,数组可以用指针表示,形参就是数组和字长
void USART_SendString(char *str,uint8_t size)
{
   uint8_t i = 0;
   for ( i = 0; i < size; i++)
   {
      USART_SendChar(str[i]);
   }
   
}

//引入外部变量
extern uint8_t buff[100];
extern uint8_t size;

//中断服务程序
void USART1_IRQHandler(void)
{
   //判断是RXNE=1还是IDLE=1
   if (USART1->SR & USART_SR_RXNE)
   {
      //如果RXNE=1,表示接收到一个字符
buff[size]=USART1->DR;
size++;
   }
   else if (USART1->SR & USART_SR_IDLE)
   {
      USART1->DR;
      //如果IDLE=1,表示检测到空闲帧,字符串接收完毕
      USART_SendString(buff,size);
      size=0;
   }
   
}

usart.h

cpp 复制代码
#ifndef __USART_H
#define __USART_H
#include "string.h"
#include "stm32f10x.h"
//初始化
void USART_Init(void);

//发送一个字符
void USART_SendChar(uint8_t ch);


//发送一个字符串,数组可以用指针表示,形参就是数组和字长
void USART_SendString(char *str,uint8_t size);


#endif

我们可以将接收字符串的标志位在外面定义出来。

4.串口案例一串口通讯_hal库轮询方式

我们有usart1配置。

我们反正还得需要配,这个时候我们可以不管他,直接去左边框栏中点点点。图形化配置的精髓就是方便。

还是调用hal库简单。

轮询方式使用效率不是很高,中断方式才高。

5.HAL库中断方式---定长数据接收

记住USART1用异步模式,要打开中断实现

中断方式要和回调函数结合。

接收定长数据,会和之前接收的数据结合分析

6.HAL库中断方式--变长数据接收

接收变长数据,size是可接收的字长上限。

她的回调不一样,是下面这个。在函数面前加void,我忘了加,编译出错。

先检查是什么模块

7.重定向printf---寄存器方式

用printf输出调试信息,打印到屏幕,没有屏幕也可重定向printf,把数据打印到串口,从而在电脑端接收调试信息,这是一种有效调试手段。

printf大法对任何语言都是有用的。

printf的底层函数:fputc

把字符一个个发到控制台文件里。

重写也在usart.c里,记得引入<stdio.h>

8.重定向------hal

usart.c里

在main函数来随便打印。

相关推荐
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
Lester_11015 天前
STM32霍尔传感器输入口设置为复用功能输入口时,还能用GPIO函数直接读取IO的状态吗
stm32·单片机·嵌入式硬件·电机控制
LCG元5 天前
低功耗显示方案:STM32L0驱动OLED,动态波形绘制与优化
stm32·嵌入式硬件·信息可视化
三佛科技-187366133975 天前
120W小体积碳化硅电源方案(LP8841SC极简方案12V10A/24V5A输出)
单片机·嵌入式硬件
z20348315205 天前
STM32F103系列单片机定时器介绍(二)
stm32·单片机·嵌入式硬件
古译汉书5 天前
【IoT死磕系列】Day 7:只传8字节怎么控机械臂?学习工业控制 CANopen 的“对象字典”(附企业级源码)
数据结构·stm32·物联网·http
Alaso_shuang5 天前
STM32 核心输入、输出模式
stm32·单片机·嵌入式硬件
脚后跟5 天前
AI助力嵌入式物联网项目全栈开发
嵌入式硬件·物联网·ai编程
2501_918126915 天前
stm32死锁是怎么实现的
stm32·单片机·嵌入式硬件·学习·个人开发
z20348315205 天前
STM32F103系列单片机定时器介绍(一)
stm32·单片机