STM32 物联网智能家居 (三) 输入子系统
STM32 物联网智能家居 (三) 输入子系统
下面是物联网智能家居的输入子系统,见下图,在输入子系统中会实现按键输入、网络输入、标准输入Scanf,其中的网络输入放入到网络子系统中进行讲解。
一、输入子系统核心功能
STM32 物联网智能家居输入子系统是一个模块化的、分层的输入管理框架,具备以下核心功能:
1. 多种输入设备的支持与抽象
2. 输入事件的统一管理与处理
3. 平台与操作系统的无关性
4. 事件的实时处理与测试
input_test()
模块,用于实时测试输入子系统。
5. 模块化设计与扩展性
6. 时间与事件的精确管理
7. 稳定性与容错性
综上所述,该输入子系统为 STM32 智能家居系统 提供了可靠、高效、可扩展的输入事件处理能力。通过模块化设计和抽象分层,无论是添加新设备还是适配不同的操作系统和硬件平台,都能快速实现。此系统不仅为物联网项目的输入管理奠定了坚实基础,还展现了优秀的代码组织与工程设计思想。
二、代码解析
1. 主进入函数 (main.c
)
在 main.c中,main()
函数作为全系统的进入点:
input_test()
测试全部输入功能,实时监测输入事件。代码详解:
int main(void)
{
HAL_Init(); // 初始化HAL库,设置系统相关的中断和时钟。
SystemClock_Config(); // 配置系统时钟,使芯片工作在目标频率。
MX_GPIO_Init(); // 初始化GPIO外设,为输入输出做准备。
MX_USART1_UART_Init(); // 初始化USART1,用于调试信息输出。
MX_USART3_UART_Init(); // 初始化USART3,用于串口通信。
ring_buffer_init(&test_buffer); // 初始化环形Buffer缓冲区。
EnableDebugIRQ();
printf("Hello World!\r\n"); // 打印调试信息,确认系统启动成功。
while (1)
{
input_test(); // 进入输入测试循环,处理输入事件。
}
}
2. 芯片抽象层 (CAL)
CAL层实现了与种类芯片相关的具体功能:
在
cal_gpio_key.c
和 cal_gpio_key.h
中实现。
CAL_GPIOKkeyInit()
函数来初始化GPIO按键。KEY_GPIO_ReInit()
;对非ST芯片将调用其实现。代码详解:
void CAL_GPIOKkeyInit(void)
{
#if defined(CONFIG_ST_HAL)
// 对于ST芯片,调用专用的GPIO初始化函数。
KEY_GPIO_ReInit();
#else
// 对于其他芯片,调用通用的GPIO初始化函数。
MY_KEY_GPIO_ReInit();
#endif
}
在
cal_time.c
和 cal_time.h
中实现 CAL_GetTime()
函数,能够从系统中获取时间。代码详解:
TIME_T CAL_GetTime(void)
{
return HAL_GetTick(); // 返回系统滴答时间,单位为毫秒。
}
3. 内核抽象层 (KAL)
在内核层,通过抽象屏蔽不同OS之间的区别:
在
kal_gpio_key.c
和 kal_gpio_key.h
中,实现了 KAL_GPIOKkeyInit()
函数:
代码详解:
void KAL_GPIOKkeyInit(void)
{
#if defined(CONFIG_NOOS)
// 对于裸机环境,直接调用芯片抽象层的GPIO初始化函数。
CAL_GPIOKkeyInit();
#elif defined(CONFIG_FREERTOS)
// 对于FreeRTOS,使用专用的初始化方案。
FreeRTOS_GPIOKkeyInit();
#elif defined(CONFIG_RTTHREAD)
// 对于RT-Thread,使用其对应的初始化方案。
RTTread_GPIOKkeyInit();
#endif
}
在
kal_time.c
和 kal_time.h
中,调用CAL层的时间函数。代码详解:
TIME_T KAL_GetTime(void)
{
return CAL_GetTime(); // 调用芯片抽象层函数获取系统时间。
}
4. 输入系统模块 (Input System)
通过 input_system.c
和 input_system.h
:
AddInputDevices()
。代码详解:
void AddInputDevices(void)
{
AddInputDeviceGPIOKey(); // 注册GPIO按键设备到系统。
}
void InitInputDevices(void)
{
PInputDevice pDev = g_ptInputDevices;
while (pDev)
{
pDev->DeviceInit(); // 初始化每个输入设备,确保其功能正常。
pDev = pDev->pNext; // 遍历链表,初始化下一个设备。
}
}
5. 输入事件环形缓冲区 (Input Buffer)
在系统中,Input Buffer 是输入事件的主要传输通道:
PutInputEvent()
GetInputEvent()
代码详解:
int PutInputEvent(PInputEvent ptInputEvent)
{
int i = (g_tInputBuffer.pW + 1) % BUFFER_SIZE; // 计算写入位置是否超出缓冲区。
if (i != g_tInputBuffer.pR) // 缓冲区未满时才允许写入。
{
g_tInputBuffer.buffer[g_tInputBuffer.pW] = *ptInputEvent; // 将事件写入缓冲区。
g_tInputBuffer.pW = i; // 更新写指针。
return 0; // 写入成功。
}
return -1; // 缓冲区已满,写入失败。
}
int GetInputEvent(PInputEvent ptInputEvent)
{
if (g_tInputBuffer.pR == g_tInputBuffer.pW) // 缓冲区为空时,返回失败。
return -1;
*ptInputEvent = g_tInputBuffer.buffer[g_tInputBuffer.pR]; // 读取缓冲区中的事件。
g_tInputBuffer.pR = (g_tInputBuffer.pR + 1) % BUFFER_SIZE; // 更新读指针。
return 0; // 读取成功。
}
6. 测试功能 (Input Test)
在 input_test.c
和 input_test.h
中,通过 input_test()
执行输入测试:
代码详解:
void input_test(void)
{
InputEvent event; // 定义输入事件结构体。
AddInputDevices(); // 注册设备,将所有输入设备加入系统。
InitInputDevices(); // 初始化设备,确保其工作状态正常。
while (1)
{
if (GetInputEvent(&event) == 0) // 从缓冲区中读取事件。
{
printf("get input event:\r\n"); // 打印事件详情。
printf("type: %d\r\n", event.eType); // 输出事件类型。
printf("time: %d\r\n", event.time); // 输出事件发生时间。
printf("key : %d\r\n", event.iKey); // 输出按键编号。
printf("pressure : %d\r\n", event.iPressure); // 输出按键压力状态。
}
}
}
三、示例演示
下面我们将程序下载到开发板中,进行Debug调试
下面运行到输入子系统的测试,通过注册按键Key设备,然后用串口进行打印信息。
下面分别按下按键Key1和按键Key2,使用串口助手打印出注册的按键事件。
四、总结
至此。通过添加设备抽象层,如GPIO键和时间监控,配合输入系统和测试,已构建了一个框架分明的物联网智能家居输入子系统。
此系统能将高度进行抽象和分层,对于事件跨芯片和平台进行多样化处理,最终展现了很好的优化效果。
五、更多精彩见ARM架构课程
作者:艾格北峰