hc32l13x ch455h 4x5矩阵键盘,数码管驱动,按键使用gpio,一个ch455h控制三个数码管,每个按键按下电亮数码管中的一个led具体实现代码
时间: 2023-12-29 18:03:54 浏览: 54
下面是一个示例的代码实现,其中使用了HC32L13X的GPIO模块和定时器模块:
```c
#include "hc32_gpio.h"
#include "hc32_timer.h"
#define LED_ON 0
#define LED_OFF 1
#define KEY_PORT GpioPortA
#define KEY_PIN GpioPin0
#define KEY_SCAN_TIME 50 // 扫描间隔时间,单位:ms
#define DIGIT_PORT GpioPortB
#define DIGIT_PIN1 GpioPin0
#define DIGIT_PIN2 GpioPin1
#define DIGIT_PIN3 GpioPin2
#define DIGIT_NUM 3 // 数码管个数
#define DIGIT_SCAN_TIME 5 // 数码管扫描间隔时间,单位:ms
#define SEG_PORT GpioPortC
#define SEG_PIN_A GpioPin0
#define SEG_PIN_B GpioPin1
#define SEG_PIN_C GpioPin2
#define SEG_PIN_D GpioPin3
#define SEG_PIN_E GpioPin4
#define SEG_PIN_F GpioPin5
#define SEG_PIN_G GpioPin6
#define SEG_PIN_DP GpioPin7
#define SEG_NUM 7 // 数码管段数
#define SEG_SCAN_TIME 5 // 数码管段扫描间隔时间,单位:ms
#define DISP_NUM 3 // 显示数字的个数
static uint8_t digit_buf[DIGIT_NUM]; // 数码管缓存
static uint8_t seg_buf[DIGIT_NUM][SEG_NUM]; // 数码管段缓存
/**
* @brief 初始化IO口
*
*/
static void init_io(void)
{
// 初始化按键IO口
Gpio_InitIO(KEY_PORT, KEY_PIN, GpioDirIn);
// 初始化数码管IO口
Gpio_InitIO(DIGIT_PORT, DIGIT_PIN1, GpioDirOut);
Gpio_InitIO(DIGIT_PORT, DIGIT_PIN2, GpioDirOut);
Gpio_InitIO(DIGIT_PORT, DIGIT_PIN3, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_A, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_B, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_C, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_D, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_E, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_F, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_G, GpioDirOut);
Gpio_InitIO(SEG_PORT, SEG_PIN_DP, GpioDirOut);
}
/**
* @brief 初始化定时器
*
*/
static void init_timer(void)
{
// 定时器0,用于按键扫描
stc_timera_init_t timera_init;
Timera_StructInit(&timera_init);
timera_init.u16Period = KEY_SCAN_TIME * (SystemCoreClock / 1000);
timera_init.pfnTimeraCb = key_scan_cb;
Timera_Init(TIMERA_UNIT, TIMERA_CH, &timera_init);
Timera_EnableIrq(TIMERA_UNIT, TIMERA_CH);
Timera_Start(TIMERA_UNIT, TIMERA_CH);
// 定时器1,用于数码管扫描
Timera_StructInit(&timera_init);
timera_init.u16Period = DIGIT_SCAN_TIME * (SystemCoreClock / 1000);
timera_init.pfnTimeraCb = digit_scan_cb;
Timera_Init(TIMERA_UNIT, TIMERA_CH, &timera_init);
Timera_EnableIrq(TIMERA_UNIT, TIMERA_CH);
Timera_Start(TIMERA_UNIT, TIMERA_CH);
// 定时器2,用于数码管段扫描
Timera_StructInit(&timera_init);
timera_init.u16Period = SEG_SCAN_TIME * (SystemCoreClock / 1000);
timera_init.pfnTimeraCb = seg_scan_cb;
Timera_Init(TIMERA_UNIT, TIMERA_CH, &timera_init);
Timera_EnableIrq(TIMERA_UNIT, TIMERA_CH);
Timera_Start(TIMERA_UNIT, TIMERA_CH);
}
/**
* @brief 数字转换为数码管段
*
* @param num 数字
* @return uint8_t 数码管段
*/
static uint8_t num_to_seg(uint8_t num)
{
const uint8_t seg_table[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f
};
if (num < sizeof(seg_table)) {
return seg_table[num];
} else {
return 0;
}
}
/**
* @brief 按键扫描回调函数
*
*/
void key_scan_cb(void)
{
static uint8_t key_state = 0;
static uint8_t key_cnt = 0;
if (Gpio_GetIO(KEY_PORT, KEY_PIN) == 0) {
key_cnt++;
if (key_cnt >= 5) {
key_state = 1;
}
} else {
if (key_state == 1) {
// 按键被按下
// TODO: 处理按键事件
}
key_state = 0;
key_cnt = 0;
}
}
/**
* @brief 数码管扫描回调函数
*
*/
void digit_scan_cb(void)
{
static uint8_t digit_idx = 0;
// 关闭上一个数码管
Gpio_WriteIO(DIGIT_PORT, DIGIT_PIN1, LED_OFF);
Gpio_WriteIO(DIGIT_PORT, DIGIT_PIN2, LED_OFF);
Gpio_WriteIO(DIGIT_PORT, DIGIT_PIN3, LED_OFF);
// 更新数码管缓存
digit_buf[digit_idx] = (digit_buf[digit_idx] + 1) % 10;
uint8_t num = digit_buf[digit_idx];
uint8_t seg = num_to_seg(num);
for (int i = 0; i < SEG_NUM; i++) {
seg_buf[digit_idx][i] = (seg >> i) & 0x01;
}
// 打开当前数码管
switch (digit_idx) {
case 0:
Gpio_WriteIO(DIGIT_PORT, DIGIT_PIN1, LED_ON);
break;
case 1:
Gpio_WriteIO(DIGIT_PORT, DIGIT_PIN2, LED_ON);
break;
case 2:
Gpio_WriteIO(DIGIT_PORT, DIGIT_PIN3, LED_ON);
break;
default:
break;
}
// 更新数码管索引
digit_idx = (digit_idx + 1) % DIGIT_NUM;
}
/**
* @brief 数码管段扫描回调函数
*
*/
void seg_scan_cb(void)
{
static uint8_t seg_idx = 0;
// 关闭上一个数码管段
Gpio_WriteIO(SEG_PORT, SEG_PIN_A, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_B, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_C, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_D, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_E, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_F, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_G, LED_OFF);
Gpio_WriteIO(SEG_PORT, SEG_PIN_DP, LED_OFF);
// 打开当前数码管段
switch (seg_idx) {
case 0:
Gpio_WriteIO(SEG_PORT, SEG_PIN_A, seg_buf[0][0]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_B, seg_buf[0][1]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_C, seg_buf[0][2]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_D, seg_buf[0][3]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_E, seg_buf[0][4]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_F, seg_buf[0][5]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_G, seg_buf[0][6]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_DP, LED_OFF);
break;
case 1:
Gpio_WriteIO(SEG_PORT, SEG_PIN_A, seg_buf[1][0]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_B, seg_buf[1][1]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_C, seg_buf[1][2]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_D, seg_buf[1][3]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_E, seg_buf[1][4]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_F, seg_buf[1][5]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_G, seg_buf[1][6]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_DP, LED_OFF);
break;
case 2:
Gpio_WriteIO(SEG_PORT, SEG_PIN_A, seg_buf[2][0]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_B, seg_buf[2][1]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_C, seg_buf[2][2]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_D, seg_buf[2][3]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_E, seg_buf[2][4]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_F, seg_buf[2][5]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_G, seg_buf[2][6]);
Gpio_WriteIO(SEG_PORT, SEG_PIN_DP, LED_OFF);
break;
default:
break;
}
// 更新数码管段索引
seg_idx = (seg_idx + 1) % SEG_NUM;
}
int main()
{
// 初始化IO口
init_io();
// 初始化定时器
init_timer();
while (1) {
// TODO: 主循环
}
}
```
需要注意的是,上述代码中的回调函数 `key_scan_cb()`、`digit_scan_cb()` 和 `seg_scan_cb()` 都是通过定时器调用的,因此需要在定时器初始化时注册这些回调函数。同时,由于定时器的中断服务函数也是在定时器回调函数中调用的,因此需要在主函数中开启全局中断以便支持定时器中断。
阅读全文