嵌入式软件--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函数来随便打印。

相关推荐
蓝斯4977 小时前
从.到实现一个Windows上的虚拟hid键盘设备
windows·单片机·计算机外设
熙芯XiChip7 小时前
硬实时与软实时RTOS核心区别
嵌入式硬件
伟大的前程8 小时前
unsigned int 定义的变量 在 电脑的 64 位系统中 和 32 位 cortex-m0 和 8 位的 51 单片机
单片机·嵌入式硬件
小渔村的拉线工8 小时前
1.HPM6E80 解析芯片整体工作原理和存储架构
单片机·嵌入式硬件·mcu·架构·hpm6e80
熙芯XiChip9 小时前
CAN与CANopen的本质区别
单片机
lilihewo9 小时前
Altium Designer 封装库的创建(分享pcb 3D封装库)
嵌入式硬件·51单片机
神罚天下ET10 小时前
典型arm位单片机启动流程(从上电到main.c)
c语言·arm开发·单片机
碧海银沙音频科技研究院11 小时前
蓝牙耳机使用WSDF5361锂保芯片进入船运模式实现方法
嵌入式硬件·算法
Zevalin爱灰灰12 小时前
模拟信号链电路——基于TL431的电压基准电路
单片机·嵌入式硬件
csdn杰哥12 小时前
瑞萨单片机开发教程[二十七] DTC 外部中断触发传输实验
单片机·嵌入式硬件·mongodb·瑞萨·ra6m5