stcTimerCfg.Tim0_CmpValue = (uint16_t)(u32Pclk1/1024ul/2ul - 1ul);
时间: 2024-05-25 10:11:30 浏览: 140
这行代码是在配置一个定时器的比较寄存器值,具体解释如下:
- `stcTimerCfg` 是一个结构体,用于配置定时器的各项参数,包括比较值、时钟源、工作模式等。
- `Tim0_CmpValue` 是结构体中的一个成员变量,表示定时器 0 的比较寄存器值。
- `(uint16_t)(u32Pclk1/1024ul/2ul - 1ul)` 是将系统时钟频率除以 1024(即定时器的时钟源),再除以 2(因为是边沿对齐模式),减去 1 后转换为 16 位的无符号整数。
- 因此,这行代码的作用是将定时器 0 的比较寄存器值设为系统时钟频率除以 2048 减 1 的值。这样配置后,当定时器 0 的计数值与比较寄存器值相等时,就会触发中断或产生其他特定的事件。
相关问题
hc32l13x实现4x5矩阵键盘,一个ch455实现按键灯光,端口复用,具体实现代码
以下是基于HC32L13X和CH455的4x5矩阵键盘按键灯光实现代码:
```c
#include "hc32l13x.h"
#define KEY_PORT GpioPortA
#define KEY_PIN GpioPin1
#define LED_PORT GpioPortB
#define LED_PIN GpioPin0
/* 矩阵键盘按键对应的行列 */
static const uint8_t matrix_key[4][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17, 18, 19, 20}
};
/* 矩阵键盘按键扫描函数 */
static uint8_t scan_key(void)
{
uint8_t i, j;
uint8_t key_val = 0;
/* 遍历每一列 */
for (i = 0; i < 5; i++) {
/* 将当前列置低 */
Gpio_WriteOutputIO(KEY_PORT, KEY_PIN + i, GpioPinReset);
/* 延时一段时间,等待列稳定 */
delay_us(10);
/* 遍历每一行 */
for (j = 0; j < 4; j++) {
/* 判断当前行是否有按键按下 */
if (!Gpio_GetInputIO(KEY_PORT, KEY_PIN + 5 + j)) {
/* 根据行列计算出按键对应的值 */
key_val = matrix_key[j][i];
/* 等待按键松开 */
while (!Gpio_GetInputIO(KEY_PORT, KEY_PIN + 5 + j));
}
}
/* 将当前列置高 */
Gpio_WriteOutputIO(KEY_PORT, KEY_PIN + i, GpioPinSet);
}
return key_val;
}
int main(void)
{
stc_gpio_config_t led_cfg;
uint8_t key_val = 0;
/* 使能GPIO外设时钟 */
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
/* 配置矩阵键盘的行为输入,列为输出 */
for (uint8_t i = 0; i < 5; i++) {
Gpio_Init(KEY_PORT, KEY_PIN + i, GpioDirOut);
Gpio_WriteOutputIO(KEY_PORT, KEY_PIN + i, GpioPinSet);
}
for (uint8_t i = 0; i < 4; i++) {
Gpio_Init(KEY_PORT, KEY_PIN + 5 + i, GpioDirIn);
Gpio_WriteOutputIO(KEY_PORT, KEY_PIN + 5 + i, GpioPinSet);
}
/* 配置LED灯为输出 */
led_cfg.enDir = GpioDirOut;
led_cfg.enDrv = GpioDrvH;
led_cfg.enPuPd = GpioPuPdUp;
led_cfg.enOD = GpioOdDisable;
Gpio_Init(LED_PORT, LED_PIN, &led_cfg);
Gpio_WriteOutputIO(LED_PORT, LED_PIN, GpioPinSet);
/* 配置定时器 */
TmrCfg();
/* 配置中断 */
IntCfg();
while (1) {
/* 扫描矩阵键盘按键 */
key_val = scan_key();
if (key_val != 0) {
/* 点亮对应的LED灯 */
Gpio_WriteOutputIO(LED_PORT, LED_PIN, GpioPinReset);
/* 发送按键值到串口 */
Uart_SendData(UARTCH1, key_val);
} else {
/* 熄灭LED灯 */
Gpio_WriteOutputIO(LED_PORT, LED_PIN, GpioPinSet);
}
}
}
/* 定时器配置函数 */
static void TmrCfg(void)
{
stc_tmr3_init_t init_struct;
/* 使能定时器3时钟 */
Sysctrl_SetPeripheralGate(SysctrlPeripheralTmr3, TRUE);
/* 配置定时器3为定时模式,计数时钟为fLRC/256,计数周期为10ms */
init_struct.enWorkMode = Tmr3WorkModeTimer;
init_struct.enCT = Tmr3Timer;
init_struct.enPRS = Tmr3PCLKDiv256;
init_struct.u16CmpValue = 2000;
Tmr3_Init(&init_struct);
/* 启动定时器3 */
Tmr3_Start();
}
/* 中断配置函数 */
static void IntCfg(void)
{
stc_irq_regi_config_t irq_config;
/* 使能外部中断INT001_IRQn */
NVIC_ClearPendingIRQ(INT001_IRQn);
NVIC_SetPriority(INT001_IRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_EnableIRQ(INT001_IRQn);
/* 配置INT1引脚为下降沿触发 */
Gpio_SetFunc_INT01_1(Gpio_INT01_1);
stc_gpio_intern_data_t stcGpioInternData;
stcGpioInternData.bTouchNvic = TRUE;
stcGpioInternData.enIntf = Gpio_IntFallEdge;
Gpio_InitInt(KEY_PORT, KEY_PIN + 5, &stcGpioInternData);
/* 配置定时器3中断 */
irq_config.enIRQn = Int001_IRQn;
irq_config.enIntSrc = INT_TMR3_GC;
irq_config.pfnCallback = Tmr3GCIntCallback;
Int_RegisterIRQ(&irq_config);
/* 使能定时器3中断 */
Tmr3_EnableIrq();
}
/* 定时器3中断回调函数 */
void Tmr3GCIntCallback(void)
{
static uint32_t cnt = 0;
/* 计数器值加1 */
cnt++;
/* 每500ms翻转一次LED灯 */
if (cnt >= 50) {
cnt = 0;
Gpio_ToggleOutIO(LED_PORT, LED_PIN);
}
}
```
以上代码中,`scan_key()` 函数为矩阵键盘按键扫描函数,通过遍历每一列和每一行来检测是否有按键按下。如果检测到按键按下,则根据行列计算出按键对应的值。
在主函数中循环调用 `scan_key()` 函数,如果返回值不为0,则表示有按键按下,点亮对应的LED灯,并将按键值发送到串口。如果返回值为0,则表示没有按键按下,熄灭LED灯。
另外,为了实现LED灯的闪烁效果,还使用了定时器和中断。在定时器中断回调函数 `Tmr3GCIntCallback()` 中,每500ms翻转一次LED灯。同时,为了实现按键灯光与LED灯的闪烁效果,将LED灯的控制与定时器中断回调函数中的代码合并。
需要注意的是,以上代码中使用到了一些宏定义和函数,如 `delay_us()`、`Sysctrl_SetPeripheralGate()`、`Gpio_Init()`、`Gpio_WriteOutputIO()`、`Gpio_GetInputIO()`、`Uart_SendData()`、`Tmr3_Init()`、`Tmr3_Start()`、`Tmr3_EnableIrq()` 等,这些需要根据具体的开发板和外设进行修改和适配。
hc32l13x 多个编码器开关,带按键功能、防抖功能、检测上升沿,正转计数增加,反转计数减少,主函数、中断函数、初始化函数分开
以下是基于HC32L13x的多个编码器开关的带按键功能、防抖功能、检测上升沿,正转计数增加,反转计数减少的实现方法:
首先,在初始化函数中需要对GPIO进行配置,包括输入/输出模式、上下拉电阻等的设置。同时,也需要对TIMER进行配置,以便于中断函数的使用。
```c
void Encoder_Init(void)
{
stc_gpio_config_t stcGpioCfg;
stc_timer3_config_t stcTimer3Cfg;
// 打开GPIO和TIMER3的时钟
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
Sysctrl_SetPeripheralGate(SysctrlPeripheralTim3, TRUE);
// 配置GPIO
Gpio_StructInit(&stcGpioCfg);
stcGpioCfg.u16PinAttr = Pin_PU;
Gpio_Init(ENCODER1_A_PORT, ENCODER1_A_PIN, &stcGpioCfg);
Gpio_Init(ENCODER1_B_PORT, ENCODER1_B_PIN, &stcGpioCfg);
Gpio_Init(ENCODER1_BTN_PORT, ENCODER1_BTN_PIN, &stcGpioCfg);
Gpio_Init(ENCODER2_A_PORT, ENCODER2_A_PIN, &stcGpioCfg);
Gpio_Init(ENCODER2_B_PORT, ENCODER2_B_PIN, &stcGpioCfg);
Gpio_Init(ENCODER2_BTN_PORT, ENCODER2_BTN_PIN, &stcGpioCfg);
// 配置TIMER3
Timer3_StructInit(&stcTimer3Cfg);
stcTimer3Cfg.u16ClkDiv = TIMER3_CLK_DIV1;
stcTimer3Cfg.u16CmpValue = 0xFFFF;
Timer3_Cfg(TIM3_CH1, &stcTimer3Cfg);
Timer3_ClrIntFlag(TIM3_CH1);
Timer3_ClrCount(TIM3_CH1);
Timer3_Cmd(TIM3_CH1, TRUE);
}
```
接着,需要编写中断函数来处理编码器的旋转和按键的触发。在中断函数中,需要判断是哪个编码器发生了变化,并根据变化的方向进行正转计数或反转计数的操作。同时,还需要对按键进行防抖处理,防止误触发。
```c
void Encoder_IRQHandler(void)
{
static uint32_t cnt1 = 0, cnt2 = 0;
static uint32_t last1 = 0, last2 = 0;
static uint32_t debounce1 = 0, debounce2 = 0;
uint32_t cur1 = Gpio_GetInputIO(ENCODER1_A_PORT, ENCODER1_A_PIN) << 1 | Gpio_GetInputIO(ENCODER1_B_PORT, ENCODER1_B_PIN);
uint32_t cur2 = Gpio_GetInputIO(ENCODER2_A_PORT, ENCODER2_A_PIN) << 1 | Gpio_GetInputIO(ENCODER2_B_PORT, ENCODER2_B_PIN);
uint32_t btn1 = Gpio_GetInputIO(ENCODER1_BTN_PORT, ENCODER1_BTN_PIN);
uint32_t btn2 = Gpio_GetInputIO(ENCODER2_BTN_PORT, ENCODER2_BTN_PIN);
// 编码器1
if (cur1 != last1)
{
if (last1 == 0x00 && cur1 == 0x01)
{
cnt1++;
}
else if (last1 == 0x01 && cur1 == 0x03)
{
cnt1++;
}
else if (last1 == 0x03 && cur1 == 0x02)
{
cnt1++;
}
else if (last1 == 0x02 && cur1 == 0x00)
{
cnt1++;
}
else if (last1 == 0x00 && cur1 == 0x02)
{
cnt1--;
}
else if (last1 == 0x02 && cur1 == 0x03)
{
cnt1--;
}
else if (last1 == 0x03 && cur1 == 0x01)
{
cnt1--;
}
else if (last1 == 0x01 && cur1 == 0x00)
{
cnt1--;
}
last1 = cur1;
}
// 编码器2
if (cur2 != last2)
{
if (last2 == 0x00 && cur2 == 0x01)
{
cnt2++;
}
else if (last2 == 0x01 && cur2 == 0x03)
{
cnt2++;
}
else if (last2 == 0x03 && cur2 == 0x02)
{
cnt2++;
}
else if (last2 == 0x02 && cur2 == 0x00)
{
cnt2++;
}
else if (last2 == 0x00 && cur2 == 0x02)
{
cnt2--;
}
else if (last2 == 0x02 && cur2 == 0x03)
{
cnt2--;
}
else if (last2 == 0x03 && cur2 == 0x01)
{
cnt2--;
}
else if (last2 == 0x01 && cur2 == 0x00)
{
cnt2--;
}
last2 = cur2;
}
// 按键1
if (btn1 == 0)
{
debounce1++;
if (debounce1 >= DEBOUNCE_TIME)
{
// 触发按键事件
// ...
}
}
else
{
debounce1 = 0;
}
// 按键2
if (btn2 == 0)
{
debounce2++;
if (debounce2 >= DEBOUNCE_TIME)
{
// 触发按键事件
// ...
}
}
else
{
debounce2 = 0;
}
Timer3_ClrIntFlag(TIM3_CH1);
}
```
最后,在主函数中调用初始化函数,并加入一个死循环来保持程序运行。
```c
int main(void)
{
// 初始化
Encoder_Init();
while (1)
{
// do something
}
}
```
需要注意的是,以上代码仅为示例代码,实际使用时需要根据硬件连接和需求进行相应的修改。
阅读全文