USART的PAL库编程 周期性任务的实现方法

USART驱动的工作原理

在这里插入图片描述
总结一下我们之前使用中断的方式来进行数据的发送和接收 如果收到数据数据在RDR寄存器中 RXNE标志位就从0到1触发中断 进入中断服务函数 把数据缓存在队列中 然后在到进程函数中断接收数据函数中进行出队处理
发送数据就是把中断关闭(标志位TXE的寄存器TDR为空的时候为1会误触发中断所以要关闭)要发送的数据进行入队然后打开中断 IDR寄存器中还是没数据
然后标志位TXE为1触发中断 进入中断服务函数把数据出队 逐个发送

USART驱动的具体使用方法

驱动概述
在这里插入图片描述
PAL库初始化USART
在这里插入图片描述
因为数据发送和数据的接收都是共同用一个中断源
所以只需要设置一个优先级分组和子优先级和抢占优先级
发送缓冲区和接收缓冲区
在这里插入图片描述
因为我们是使用中断的方式发送和接收数据的 PAL库中 所以要把数据缓存在队列中也就是缓冲区 但是这个队列不能太长因为队列占用的是RAM 芯片的RAM收到限制
PAL库函数的初始化

	hUSART1.Init.USARTx = USART1;
	hUSART1.Init.BaudRate = 9600;
	hUSART1.Init.USART_WordLength = USART_WordLength_8b;
	hUSART1.Init.USART_StopBits = USART_StopBits_1;
	hUSART1.Init.USART_Parity = USART_Parity_No;
	hUSART1.Init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	hUSART1.Init.USART_IRQ_PreemptionPriority = 0;
	hUSART1.Init.USART_IRQ_SubPriority = 0;
	hUSART1.Init.TxBufferSize = 128;//缓冲区的长度
	hUSART1.Init.RxBufferSize = 128;//缓冲区的长度
	hUSART1.Init.Advanced.Remap = 1;//启用复用功能 AFIO
	hUSART1.Init.Advanced.LineSeparator = LineSeparator_CRLF; // \r\n
	PAL_USART_Init(&hUSART1);

编写PAL库的中断服务函数
在这里插入图片描述
具体代码

void USART1_IRQHandler(void)
{
	PAL_USART_IRQHandler(&hUSART1);
}

数据的发送
在这里插入图片描述
数据的接收
在这里插入图片描述
time out (超时值)在这里插入图片描述如果在调用这个函数接口 对应传入的的TIME out值就如上图所示
数据的接收
在这里插入图片描述

PAL_USART_ReadLine 在使用这个函数接口之前先要设置行分隔符的方式 行分隔符就是\r \r\n 等多种分隔行 在初始化的时候调用高级参数
在这里插入图片描述
char strBuffer[64];设置为64即可

#include "stm32f10x.h"
#include "stm32f10x_pal.h"
#include "stm32f10x_pal_usart.h"

static PalUSART_HandleTypeDef hUSART1;//声明句柄



int main(void)
{
	PAL_Init();
	
	hUSART1.Init.USARTx = USART1;
	hUSART1.Init.BaudRate = 9600;
	hUSART1.Init.USART_WordLength = USART_WordLength_8b;
	hUSART1.Init.USART_StopBits = USART_StopBits_1;
	hUSART1.Init.USART_Parity = USART_Parity_No;
	hUSART1.Init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	hUSART1.Init.USART_IRQ_PreemptionPriority = 0;
	hUSART1.Init.USART_IRQ_SubPriority = 0;
	hUSART1.Init.TxBufferSize = 128;//缓冲区的长度
	hUSART1.Init.RxBufferSize = 128;//缓冲区的长度
	hUSART1.Init.Advanced.Remap = 1;//启用复用功能 AFIO
	hUSART1.Init.Advanced.LineSeparator = LineSeparator_CRLF; // \r\n
	PAL_USART_Init(&hUSART1);
	
	
	
	
	//	// 1. 发送单个字节 0x5a
//	PAL_USART_SendByte(&hUSART1, 0x5a);
	
//	// 2. 发送字节数组 01 02 03 04 05
//	const uint8_t a[] = {1,2,3,4,5};
//	
//	PAL_USART_SendBytes(&hUSART1, a, sizeof(a)/sizeof(uint8_t));

//  // 3. 发送单个字符 H
//	PAL_USART_PutChar(&hUSART1, 'H');

//  // 4. 发送字符串Hello world\r\n
//	PAL_USART_SendString(&hUSART1, "Hello world\r\n");
  
//	// 5. 发送格式化字符串
//	const char *name = "Tom";
//	uint32_t age = 18;
//	float height = 173.5;
//	
//	PAL_USART_Printf(&hUSART1, "\r\nName:%s\r\nAge:%d\r\nHeight:%.1fcm\r\n", name, age, height);
//	

//  // 1. 接收单个字节
//	PAL_USART_SendString(&hUSART1, "Receive single byte...");
//	uint8_t byteRcvd;
//	byteRcvd = PAL_USART_ReceiveByte(&hUSART1, PAL_MAX_DELAY);
//	PAL_USART_Printf(&hUSART1, "Byte received: 0x%02x\r\n", byteRcvd);

//  // 2. 接收5个字节
//	PAL_USART_SendString(&hUSART1, "Receive 5 bytes ...");
//	
//	uint8_t a[5];
//	PAL_USART_ReceiveBytes(&hUSART1, a, 5, PAL_MAX_DELAY);
//	
//	PAL_USART_Printf(&hUSART1, "5 bytes received: %02x %02x %02x %02x %02x", a[0], a[1], a[2], a[3], a[4]);

  // 3. 接收一行字符串
	PAL_USART_SendString(&hUSART1, "Receive a line ...\r\n");
	char strBuffer[64];
	PAL_USART_ReadLine(&hUSART1, strBuffer, sizeof(strBuffer) / sizeof(char), PAL_MAX_DELAY);
	
	PAL_USART_Printf(&hUSART1, "Line received: %s\r\n", strBuffer);
	
	
	while(1)
	{
	}
}

void USART1_IRQHandler(void)
{
	PAL_USART_IRQHandler(&hUSART1);
}

应用实例

使用PAL库函数来编写Echo实验
在这里插入图片描述
我们只需要在中断响应函数中初始化PAL库函数的中断函数就行 不需要过多的代码 如果使用readline收到了字符数据 (就是这个函数的返回值大于0)
就再把这个字符给发送回去
使用USART3进行编程

在这里插入图片描述
Echo实验

#include "stm32f10x.h"
#include "stm32f10x_pal.h"
#include "stm32f10x_pal_usart.h" //引用头文件

static void Echo_Proc_Init(void);//初始化函数
static void Echo_Proc(void); //进程函数

static PalUSART_HandleTypeDef hUSART3;//声明句柄

int main(void)
{
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	PAL_Init();
	Echo_Proc_Init();
	while(1)
	{
		 Echo_Proc();
	}
}

void USART3_IRQHandler(void)
{
	
	
	PAL_USART_IRQHandler(&hUSART3); 
	
}

void Echo_Proc_Init(void)
{
		hUSART3.Init.USARTx = USART3;
		hUSART3.Init.BaudRate =9600;
		hUSART3.Init.USART_WordLength = USART_WordLength_8b;
		hUSART3.Init.USART_Parity = USART_Parity_No;
		hUSART3.Init.USART_StopBits = USART_StopBits_1;
		hUSART3.Init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
		hUSART3.Init.USART_IRQ_PreemptionPriority =0;
		hUSART3.Init.USART_IRQ_SubPriority = 0;
		hUSART3.Init.TxBufferSize = 128;//设置缓冲区大小
		hUSART3.Init.RxBufferSize = 128;
		hUSART3.Init.Advanced.LineSeparator = LineSeparator_CRLF;//设置高级参数
		PAL_USART_Init(&hUSART3);

}

void Echo_Proc()
{
		char strRcvd[64];
		if(PAL_USART_ReadLine(&hUSART3,strRcvd,64,0) >0)
		{
			
				PAL_USART_SendString(&hUSART3,strRcvd);
		}


}

串口打印日志

在这里插入图片描述
分为三个等级 第一个就是信息info 第二个就是警告 第三个就是错误

#include "stm32f10x.h"
#include "stm32f10x_pal.h"
#include "stm32f10x_pal_usart.h" //引用头文件
#include <string.h>

static void Echo_Proc_Init(void);//初始化函数
static void Echo_Proc(void); //进程函数

static PalUSART_HandleTypeDef hUSART3;//声明句柄

int main(void)
{
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	PAL_Init();
	Echo_Proc_Init();
	PAL_USART_Log(&hUSART3,WarningLevel_Info,"Initialize complele");
	while(1)
	{
		 Echo_Proc();
	}
}

void USART3_IRQHandler(void)
{
	
	
	PAL_USART_IRQHandler(&hUSART3); 
	
}

void Echo_Proc_Init(void)
{
		hUSART3.Init.USARTx = USART3;
		hUSART3.Init.BaudRate =9600;
		hUSART3.Init.USART_WordLength = USART_WordLength_8b;
		hUSART3.Init.USART_Parity = USART_Parity_No;
		hUSART3.Init.USART_StopBits = USART_StopBits_1;
		hUSART3.Init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
		hUSART3.Init.USART_IRQ_PreemptionPriority =0;
		hUSART3.Init.USART_IRQ_SubPriority = 0;
		hUSART3.Init.TxBufferSize = 128;//设置缓冲区大小
		hUSART3.Init.RxBufferSize = 128;
		hUSART3.Init.Advanced.LineSeparator = LineSeparator_CRLF;//设置高级参数
		PAL_USART_Init(&hUSART3);
	

}

void Echo_Proc()
{
		char strRcvd[64];
		if(PAL_USART_ReadLine(&hUSART3,strRcvd,64,0) >0)//参数分别为句柄的指针 用来存数据的数组名称 strRcvd 数组大小 Timeout
		{
				
				PAL_USART_Log(&hUSART3,WarningLevel_Info,"string recvd, length:%d",strlen(strRcvd));
				PAL_USART_SendString(&hUSART3,strRcvd);
		}


}

在这里插入图片描述

串口波形监控

#include "stm32f10x.h"
#include "stm32f10x_pal.h"
#include "stm32f10x_pal_usart.h"
#include  <math.h>

static PalUSART_HandleTypeDef hUSART3;
static void WaveformGenerato_Init(void);
static void WaveformGenerator_Proc(void);
int main(void)
{
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	PAL_Init();
	WaveformGenerato_Init();
	
	while(1)
	{
		WaveformGenerator_Proc();
		PAL_Delay(10);
		
	}
}


void WaveformGenerato_Init(void)
{
		hUSART3.Init.USARTx = USART3;
		hUSART3.Init.BaudRate = 115200; //显示波形的软件中波特率为115200
		hUSART3.Init.USART_WordLength = USART_WordLength_8b;
		hUSART3.Init.USART_Parity = USART_Parity_No;
		hUSART3.Init.USART_StopBits = USART_StopBits_1;
		hUSART3.Init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
		hUSART3.Init.USART_IRQ_PreemptionPriority =0; 
		hUSART3.Init.USART_IRQ_SubPriority =  0; //用到了中断就要设置中断优先级的分组 NVIC_PriorityGroupConfig
		hUSART3.Init.TxBufferSize = 128;
		hUSART3.Init.RxBufferSize = 128;
		hUSART3.Init.Advanced.LineSeparator = LineSeparator_CRLF;//设置高级参数
		PAL_USART_Init(&hUSART3);
}

void WaveformGenerator_Proc(void)
{
		float t ,y1,y2;
		t = 	PAL_GetTick()/1000.0 ; //使用这个函数就获得ms 需要除以1000.0获得秒 但是这里是float类型的需要除以1000.0
		
		y1 = sin(10*t);//yi的纵坐标
		y2 = cos(10*t);//y2的纵坐标
	
		PAL_USART_Printf(&hUSART3,"$%.3f %.3f;" ,y1,y2);//输出的特定格式
	
 
}

 
 
 void USART3_IRQHandler(void)
{
	 
		PAL_USART_IRQHandler(&hUSART3);
 	 
	 
}

在这里插入图片描述

周期性任务的实现方法

例如我们想要一个进程每隔10ms进行一次 但是又不能在while语句中添加延时函数 所以需要解决这个问题
在这里插入图片描述
想象一下一个人从0开始跑步 比如他跑到了0这个地方碰到了棋子就把棋子扔向10ms的地方(跑过去需要10ms)然后跑向那个棋子 然后棋子到了10这个地方他从0跑到10经过了10ms然后又把棋子扔向20这个地方 跑过去有需要10ms 所以程序也是如此 第一行static uint64_t nextExecTime 就是下次程序要执行的时间 if语句的判断条件就是如果当前的时间等于下次的时间就执行一次任务 然后把这个任务丢到下次运行到需要10ms的地方 从而使得一个任务每个10ms执行一次。


{
			float t ,y1,y2;
		static uint64_t nextExecTime = 0;
		if(PAL_GetTick() >= nextExecTime)
		{
				
				t = 	PAL_GetTick()/1000.0 ; //使用这个函数就获得ms 需要除以1000.0获得秒 但是这里是float类型的需要除以1000.0
				
				y1 = sin(10*t);//yi的纵坐标
				y2 = cos(10*t);//y2的纵坐标
			
				PAL_USART_Printf(&hUSART3,"$%.3f %.3f;" ,y1,y2);//输出的特定格式
				
				nextExecTime+=10;
		
		}
		
		
	
 

如果以后想要一个进程函数每隔10ms执行一次
只需要调用PAL库函数中的宏
在这里插入图片描述

	PAL_PERIODIC_PROC(10);  //调用这个宏就可以使得进程函数周期性的调用10ms
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值