本帖最后由 xld0932 于 2022-7-2 19:46 编辑
概述 CW32F030CxTx StartKit开发板板载了三个按键,一个是用于复位芯片的RESET按键,另外两个是可用户自定义的编程按键,通过原理图知道KEY1/KEY2分别与PA1/PA2相连接,本文将结合开源的MultiButton软件库现实现这两个按键的多态功能;为了能够实时监测/查看按键状态,我们还配置了USART串口实现了printf的功能,当然为了后面的调试方便,基于USART还移植了Letter-shell_3.x软件库,为后面调试、或者是发送shell命令调用软件代码功能先做好准备,当前本文先讲述一下移植,具体应用到后面使用的时候再详细描述。
MultiButton MultiButton是一个小巧装简单易用的事件驱动型按键驱动模块,使用C语言实现,它是基于面向对象方式设计思路实现的,每个按键对象都会单独使用一份数据结构来管理,所以MultiButton可以无限量的扩展按键,其按键事件的回调异步处理方式可以简化程序结构,去除了冗余的按键处理硬编码,让按键业务逻辑更清晰。详情可以参考如下链接:https://github.com/0x1abin/MultiButton
MultiButton包含了7种类型的按键事件,如下所示:
MultiButton的使用方法也很简单,下面将一步步来进行讲解…… struct Button button1 - 初始化按键对象,此时需要绑定这个按键的GPIO端口引脚电平读取接口函数read_pin_level(),后面两个参数是按键有效触发的电平值和按键ID号,这个ID号必须是唯一值,不能重复哦
button_init(&button1, read_pin_level, 0, 1) - 注册按键事件,用户可以根据应用功能的需要对相应的按键注册一个或者多个事件,然后在回调函数里面实现用户按键的具体功能
button_attach(&button1, SINGLE_CLICK, BTN_SingleClickHandler) button_attach(&button1, DOUBLE_CLICK, BTN_DoubleClickHandler) button_start(&button1) - 设置一个循环调用后台的处理函数,我们使用上一节讲到的MultiTimer来实现这个功能,调用button_ticks()函数即可。
MultiButton实现代码 MultiTimer KEY_MultiTimer;
struct Button KEY1;
struct Button KEY2;
uint8_t key1_pin_level(void)
{
return GPIO_ReadPin(CW_GPIOA, GPIO_PIN_1);
}
uint8_t key2_pin_level(void)
{
return GPIO_ReadPin(CW_GPIOA, GPIO_PIN_2);
}
void KEY_PressDownHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Press Down"); break;
case 2 : printf("\r\nKEY2 : Press Down"); break;
default: break;
}
}
void KEY_PressUpHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Press Up"); break;
case 2 : printf("\r\nKEY2 : Press Up"); break;
default: break;
}
}
void KEY_PressRepeatHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Press Repeat"); break;
case 2 : printf("\r\nKEY2 : Press Repeat"); break;
default: break;
}
}
void KEY_SingleClickHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Single Click"); break;
case 2 : printf("\r\nKEY2 : Single Click"); break;
default: break;
}
}
void KEY_DoubleClickHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Double Click"); break;
case 2 : printf("\r\nKEY2 : Double Click"); break;
default: break;
}
}
void KEY_LongPressStartHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Long Press Start"); break;
case 2 : printf("\r\nKEY2 : Long Press Start"); break;
default: break;
}
}
void KEY_LongPressHoldHandler(void *btn)
{
Button *key = btn;
switch(key->button_id)
{
case 1 : printf("\r\nKEY1 : Long Press Hold"); break;
case 2 : printf("\r\nKEY2 : Long Press Hold"); break;
default: break;
}
}
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pins = GPIO_PIN_1 | GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
button_init(&KEY1, key1_pin_level, GPIO_Pin_RESET, 1);
button_init(&KEY2, key2_pin_level, GPIO_Pin_RESET, 2);
button_attach(&KEY1, PRESS_DOWN, KEY_PressDownHandler);
button_attach(&KEY1, PRESS_UP, KEY_PressUpHandler);
button_attach(&KEY1, PRESS_REPEAT, KEY_PressRepeatHandler);
button_attach(&KEY1, SINGLE_CLICK, KEY_SingleClickHandler);
button_attach(&KEY1, DOUBLE_CLICK, KEY_DoubleClickHandler);
button_attach(&KEY1, LONG_PRESS_START, KEY_LongPressStartHandler);
button_attach(&KEY1, LONG_PRESS_HOLD, KEY_LongPressHoldHandler);
button_attach(&KEY2, SINGLE_CLICK, KEY_SingleClickHandler);
button_start(&KEY1);
button_start(&KEY2);
MultiTimerStart(&KEY_MultiTimer, 5, KEY_MultiTimerCallback, "KEY Scan");
}
void KEY_MultiTimerCallback(MultiTimer *timer, void *userData)
{
button_ticks();
MultiTimerStart(&KEY_MultiTimer, 5, KEY_MultiTimerCallback, "KEY Scan");
}
运行结果
Letter-shell_3.x Letter-shell是一个用C语言来编写的,可以嵌入在程序中的嵌入式shell,主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数。其实从早期的2.x版本就已经开发开使用了,相比于其它shell来说操作更为方便,增加shell指令的方式也更为灵活;在CW32芯片上是首次基于USART来移植Letter-shell_3.x的版本,相对于功能而言,新版本增加了用户管理、权限管理、以及对文件系统的初步支持;但对于移植来说,最大的体会就是修改了读写函数的原型,提升了效率;还有就是在Letter-shell_3.x版本上需要申请一片缓冲区,其它的与Letter-shell_2.x的移植大体一致,详情可以参考如下链接:https://github.com/NevermindZZT/letter-shell,费话不多说,直接上代码: Shell shell;
char shellBuffer[512];
signed short shellPortRead(char *data, unsigned short len)
{
return len;
}
signed short shellPortWrite(char *data, unsigned short len)
{
for(unsigned short i = 0; i < len; i++)
{
USART_SendData_8bit(CW_UART1, *data++);
while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXE) == RESET);
}
while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXBUSY) != RESET);
return len;
}
void shellPortInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_GPIOA, ENABLE);
RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_UART1, ENABLE);
PA08_AFx_UART1TXD();
PA09_AFx_UART1RXD();
GPIO_InitStructure.Pins = GPIO_PIN_8;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pins = GPIO_PIN_9;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_Over = USART_Over_16;
USART_InitStructure.USART_Source = USART_Source_PCLK;
USART_InitStructure.USART_UclkFreq = 64000000;
USART_InitStructure.USART_StartBit = USART_StartBit_FE;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(CW_UART1, &USART_InitStructure);
NVIC_SetPriority(UART1_IRQn, 0);
NVIC_EnableIRQ(UART1_IRQn);
USART_ITConfig(CW_UART1, USART_IT_RC, ENABLE);
shell.read = shellPortRead;
shell.write = shellPortWrite;
shellInit(&shell, shellBuffer, sizeof(shellBuffer));
}
void shellPortHandler(void)
{
if(USART_GetITStatus(CW_UART1, USART_IT_RC) != RESET)
{
shellHandler(&shell, USART_ReceiveData_8bit(CW_UART1));
USART_ClearITPendingBit(CW_UART1, USART_IT_RC);
}
}
int fputc(int ch, FILE *f)
{
USART_SendData_8bit(CW_UART1, (uint8_t)ch);
while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXE) == RESET);
while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXBUSY) == SET);
return ch;
}
运行结果
工程源码
|