上一张我们构建了设备输入层构建。本节我们基于这个架构上进行串口注册
代码参考了吃肉同学的作业,已获得他的允许发表文章
本文代码并非完整,只贴了核心部分
/*----------------------------------------------------正文从这里开始----------------------------------------------------*/
第一部分
模仿GPIO的方式,我们首先在Input文件夹里面创建一个C文件,用来注册串口输入
按照gpio_key.c的规律,我取名为usart_msg.c
[usart_msg.c]
/*为串口构造一个InputDevice*/
static int USARTMsgInit(void)
{
KAL_USARTMsgInit();
return 0;
}
static InputDevice g_tUSARTDevice = {
"usart_msg", //设备名字
NULL, //依旧是通过中断实现InputEvent的打包和发送,所以这里依然是NULL
USARTMsgInit, //初始化函数
NULL, //退出函数
//此处还应有一个struct InputDevice *pNext成员,链表Next指针会在下面函数中赋值,因此这里先空着
};
void AddInputDeviceUSARTMsg(void)
{
InputDeviceRegister(&g_tUSARTDevice);
}
?初始化函数KAL_USARTMsgInit()在KAL层里面
[kal_usart_msg.c]
void KAL_USARTMsgInit(void)
{
/*裸机:注册中断*/
CAL_USARTMsgInitForChip();
/*RTOS:创建任务*/
/*此处放RTOS的代码*/
}
继续递进,到CAL层
[cal_usart_msg.c]
void CAL_USARTMsgInitForChip(void)
{
//调用芯片相关代码,注册GPIO中断
MX_USART1_UART_Init();
}
此处进行usart的最底层的初始化,由于我们在使用STM32CUBEMX时已经对UART进行初始化,函数在usart.c中已经写好,并在main.c中已经调用(代码如下所示),因此这里我们写不写都可以,心里清楚就好
[usart.c]
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
/*---------------------------------------------------------分割线---------------------------------------------------------*/
第二部分
完成了Init函数,我们接下来要实现信息的传递,也就是在中断中打包InputEvent并发送出去
例程之前已经写过串口中断函数了,driver_usart.c放在ModuleDrivers文件夹中,打开它修改一下
[driver_usart.c]
/*我们是接收完字符串之后用strcpy函数送进InputEvent的str中的,这里创建一个字符数组用于临时存放字符串。INPUT_BUF_LEN是input_system.h中的宏定义,是InputEvent结构体中的str数组容量*/
volatile static unsigned char Tmp[INPUT_BUF_LEN] = {0};
volatile static unsigned char Cnt = 0; //字符数组下标
static volatile uint8_t ucTxcplt = 0; // 发送完成标志,1完成0未完成
static volatile uint8_t ucRxcplt = 0; // 接收完成标志,1完成0未完成
static volatile uint16_t USART1_RX_LEN = 0; //接收标记
extern ring_buffer test_buffer; //我们在main.c中全局定义了一个环形缓冲区,专门用来放信息的,借来用用
只需要改写一下中断服务函数,我们用到的是RXNE位
[driver_usart.c]
void USART1_IRQHandler(void)
{
unsigned char uctemp = 0; //创建一个变量用来接收字符
InputEvent event; //创建一个事件结构体
/*判断USART1的状态寄存器的RXNE位是否被置位*/
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET)
{
/*有数据就存放到临时变量中,只读取一个字节,超时时间1秒*/
HAL_UART_Receive(&huart1,&uctemp,1,1000);
/*将数据保存到环形缓冲区中*/
ring_buffer_write(uctemp, &test_buffer);
Tmp[Cnt] = uctemp;
if(uctemp == '\n' || (Cnt+2 == INPUT_BUF_LEN))
{
event.time = KAL_GetTime();
event.eType = INPUT_EVENT_TYPE_STDIO;
event.iKey = 0;
event.iPressure = 0;
/*把字符串打包发到InputEvent结构体的str中,使用strcpy记得包含string.h*/
strcpy(event.str,(const char*)Tmp);
PutInputEvent(&event); //发送事件
Cnt = 0; //字符数组下标清零
/*清空临时存放数组中的内容,使用memset记得包含string.h*/
memset( (void *)Tmp,0, INPUT_BUF_LEN);
}
else
{
Cnt++;
}
//RXNE读完硬件清除了,不用手动了
/*HAL库中的UART统一中断服务函数,通过形参判断是要处理谁的中断*/
HAL_UART_IRQHandler(&huart1);
}
效果如下图所示
|