打印
[CW32L083系列]

LCD计数器

[复制链接]
1127|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lulugl|  楼主 | 2023-6-18 08:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 lulugl 于 2023-6-18 08:28 编辑

【目的】实现一个计数器,按下按键1开始计时,再次按下按键1实现暂停,再次按下,继续计时。按下按键2实现清零。
【实现步骤】
1、初始化时钟,代码如下:
void RCC_Configuration(void)
{
    /* 0. HSI使能并校准 */
//  RCC_HSI_OUT();
    RCC_HSI_Enable(RCC_HSIOSC_DIV6);

    /* 1. 设置HCLK和PCLK的分频系数 */
    RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
    RCC_PCLKPRS_Config(RCC_PCLK_DIV1);

//  RCC_HCLK_OUT();

//   __breakpoint(0);

    /* 2. 使能PLL,通过HSI倍频到64MHz */
    RCC_PLL_Enable(RCC_PLLSOURCE_HSI, 8000000, RCC_PLL_MUL_8); // HSI 默认输出频率8MHz
//  RCC_PLL_OUT();

    ///< 当使用的时钟源HCLK大于24M,小于等于48MHz:设置FLASH 读等待周期为2 cycle
    ///< 当使用的时钟源HCLK大于48M,小于等于72MHz:设置FLASH 读等待周期为3 cycle
    __RCC_FLASH_CLK_ENABLE();
    FLASH_SetLatency(FLASH_Latency_3);

    /* 3. 时钟切换到PLL */
    RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);
    RCC_SystemCoreClockUpdate(64000000);

    /* 4. 配置外设时钟 */
//  __RCC_GPIOF_CLK_ENABLE();
//  __RCC_GPIOE_CLK_ENABLE();
//  __RCC_GPIOD_CLK_ENABLE();
//  __RCC_GPIOC_CLK_ENABLE();
//  __RCC_GPIOB_CLK_ENABLE();
//  __RCC_GPIOA_CLK_ENABLE();
//  __RCC_LCD_CLK_ENABLE();

}
2. 初始化按键
板载按键1为PA4,按键2为PA5,根据原理图,都接了上位电阻,所以需要配置为下拉中断触发。
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* 配置PA4、PA5为按键输入 */

    GPIO_InitStruct.IT = GPIO_IT_FALLING;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pins = GPIO_PIN_4 | GPIO_PIN_5;

    __RCC_GPIOA_CLK_ENABLE();
    GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
}


3、中断配置
void NVIC_Configuration(void)
{
    __disable_irq();
//  NVIC_EnableIRQ(WDT_IRQn);
    NVIC_SetPriority(GPIOA_IRQn, 0);
//  NVIC_SetPriority(SysTick_IRQn, 1);
    NVIC_EnableIRQ(GPIOA_IRQn);
    __enable_irq();
}
4、中断回调函数,在中断回调中只清除中断标志,业务处理在主函数中处理:
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] This funcation handles GPIOA
*/
void GPIOA_IRQHandler(void)
{

                CW_GPIOA->ICR = 0; //清除中断标志

}
5、LCD驱动
在LCD驱动中,我们初始化LCD(具体见官方示例),然后是书写LCD数字显示驱动,具体代码如下:
#include "lcd.h"
//      7              6              5            4      3           2              1                         0
// RAM01  RAM00   RAM03  RAM02   RAM801  RAM10                                   RAM13  RAM12              RAM92  RAM91




/*  段码低8(左) */
static uint8_t num_L[10] = {
        0x0d, //0
        0x00, //1
        0x0e, //2
        0x0a, //3
        0x03, //4
        0x0b,  //5
        0x0f,  //6
        0x00,  //7
        0x0f,  //8
        0x0b,  //9
};
/*  段码高8(右) */
static uint8_t num_H[10] = {
        0x07,
        0x06,
        0x03,
        0x07,//3
        0x06,//4
        0x05, //5
        0x05, //
        0x07, //7
        0x07, //8
        0x07, //9
};
void show_nums(uint32_t num)
{
        uint8_t i=0;
        uint8_t j;
        uint32_t temp;
        temp = num;
        //空显示
        CW_LCD->RAM0 = 0;
  CW_LCD->RAM1 = 0;
  CW_LCD->RAM8 = 0;
  CW_LCD->RAM9 = 0;
        if(temp == 0)
                show_num(0,0);
        while(temp>0)
        {
                j = temp%10;
                show_num(i,j);
                temp /=10;
                i++;
        }
}


void show_num(uint8_t wei, uint8_t num)
{

        switch(wei)
        {
                case 7:
                {
                                //显示第7个数码管
                        CW_LCD->RAM0 |= num_H[num]<<8 | num_L[num];
                        
                        break;
                }
                case 6:
                {
                        //显示第6个数码管
                        CW_LCD->RAM0 |= (num_H[num]<<8 | num_L[num]) <<16;
                        break;
                }
                case 5:
                {
                        //显示第5个数码管
                        CW_LCD->RAM1 |= num_L[num];
                        CW_LCD->RAM8 |= num_H[num];
                        break;
                }
                case 4:
                {
                        //显示第4个数码管
                        CW_LCD->RAM8 |= num_H[num]<<16 | num_L[num]<<8;
                        break;
                }
                case 3:
                {
                        //显示第3个数码管
                        CW_LCD->RAM8 |= num_L[num]<<24;
      CW_LCD->RAM9 |= num_H[num];
                        break;
                }
                case 2:
                {
                        //显示第2个数码管
                        CW_LCD->RAM9 |= num_H[num]<<16 | num_L[num]<<8;
                        break;
                }
                case 1:
                {
                        //显示第1个数码管
                        CW_LCD->RAM1 |= num_H[num]<<8;
                        CW_LCD->RAM9 |= num_L[num]<<24;
                        break;
                }
                case 0:
                {
                        //显示第0个数码管
                        CW_LCD->RAM1 |= num_H[num]<<24 | num_L[num]<<16;
                        break;
                }
        }
                                
}

void LCD_Configuration(void)
{
    LCD_InitTypeDef LCD_InitStruct = {0};

    LCD_InitStruct.LCD_Bias = LCD_Bias_1_3;
    LCD_InitStruct.LCD_ClockSource = LCD_CLOCK_SOURCE_LSI;
    LCD_InitStruct.LCD_Duty = LCD_Duty_1_4;
    LCD_InitStruct.LCD_ScanFreq = LCD_SCAN_FREQ_256HZ;
    LCD_InitStruct.LCD_VoltageSource = LCD_VoltageSource_Internal;

    __RCC_LCD_CLK_ENABLE();
    RCC_LSI_Enable();
    LCD_Init(&LCD_InitStruct);     //基本配置
    // BTL004 LCD 对应的连接
    //PA12 COM3
    //PA11 COM2
    //PA10 COM1
    //PA09 COM0
    //PA08 SEG0
    //PC09 SEG1
    //PC08 SEG2
    //PC07 SEG3
    //PC06 SEG4
    //PD15 SEG32
    //PD14 SEG33
    //PD13 SEG34
    //PD12 SEG35
    //PD11 SEG36
    //PD10 SEG37
    //PD09 SEG38
    //PD08 SEG39
    //PB15 SEG5
    //PB14 SEG6
    //PB13 SEG7
    // 分配引脚
    LCD_COMConfig(LCD_COM0 | LCD_COM1 | LCD_COM2 | LCD_COM3, ENABLE);
    LCD_SEG0to23Config(0x0000FF, ENABLE);
    LCD_SEG32to55Config(0x0000FF,ENABLE);



    CW_LCD->RAM[0] = 0;
    CW_LCD->RAM[1] = 0;
    CW_LCD->RAM2 = 0;
    CW_LCD->RAM3 = 0;
    CW_LCD->RAM4 = 0;
    CW_LCD->RAM5 = 0;
    CW_LCD->RAM6 = 0;
    CW_LCD->RAM7 = 0;
    CW_LCD->RAM8 = 0;
    CW_LCD->RAM9 = 0;
    CW_LCD->RAM10 = 0;
    CW_LCD->RAM11 = 0;
    CW_LCD->RAM12 = 0;
    CW_LCD->RAM13 = 0;

    LCD_Cmd(ENABLE);
    CW_LCD->RAM0 = 0x0f0f;
    LCD_ContrastConfig(LCD_Contrast_Level_2);
    LCD_DriveVoltageConfig(LCD_INRS_LEVEL_0);
}
5、主函数中,我们检查按键1、按键2,并做出相应的处理。具体代码如下:
#include "main.h"
void NVIC_Configuration(void);
void RCC_Configuration(void);
uint8_t Key1Count = 0;
uint8_t Key2Count = 0;
int32_t main(void)
{
    uint32_t show_conut=0;
                uint32_t time_count = 0;
        
    CW_SYSCTRL->AHBEN_f.GPIOC = 1U;    //Open GPIOA Clk

    CW_GPIOC->ANALOG_f.PIN2 = 0U;      //Digital
    CW_GPIOC->BRR_f.BRR2 = 1U;         //Reset PA00
    CW_GPIOC->DIR_f.PIN2 = 0U;         //Output
                RCC_Configuration();
                GPIO_Configuration();
                NVIC_Configuration();
                LCD_Configuration();
          show_nums(show_conut);
    while(1)
    {
        
                        if(PA04_GETVALUE() == 0)
        {
                                        FirmwareDelay( 20000 );
                                        if(PA04_GETVALUE() == 0)
                                        {
            Key1Count++;
                                        }
        }
                        if(PA05_GETVALUE() == 0)
        {
                                        FirmwareDelay( 20000 );
                                        if(PA05_GETVALUE() == 0)
                                        {
            Key2Count++;
                                        }
        }
                                //如果按下2暂停显示
                        if(Key1Count == 2 )
                        {
                                Key1Count=0;
                        }
                        //按下K2清零,停止显示
                        if(Key2Count==1)
                        {
                                show_conut = 0;
                                Key1Count = 0;
                                Key2Count = 0;
                                show_nums(show_conut);
                        }
                        FirmwareDelay( 200 );
                        time_count ++;
                        if(time_count > 1000)
                        {
                                time_count = 1;
                                //如果按下1开始显示
                                if(Key1Count ==1)
                                {
                                        show_conut ++;
                                        show_nums(show_conut);
                                }
                                //溢出清零
                                if(show_conut==65535)
                                {
                                        show_conut=0;
                                }
                                //翻转LED1
                                CW_GPIOC->TOG = bv2;
                        }

    }

}

具体效果见视频:
附工程代码: mypro_LCD.zip (358.76 KB)

使用特权

评论回复
沙发
tpgf| | 2023-7-7 11:46 | 只看该作者
如果一直没有重新计时而超出数据范围了怎么办呢

使用特权

评论回复
板凳
wowu| | 2023-7-7 12:18 | 只看该作者
超过计数值的数据范围的时候会有报警的措施吗

使用特权

评论回复
地板
lulugl|  楼主 | 2023-7-7 12:39 | 只看该作者
wowu 发表于 2023-7-7 12:18
超过计数值的数据范围的时候会有报警的措施吗

这个可以自己设置。可以实现的!

使用特权

评论回复
5
paotangsan| | 2023-7-7 12:40 | 只看该作者
如果一直计时下去而不复位或者清零 那么需要有一个溢出情况的处理函数吧

使用特权

评论回复
6
xiaoqizi| | 2023-7-7 13:45 | 只看该作者
这种根据按键来进行操作的代码里边是不是需要添加防抖啊

使用特权

评论回复
7
lulugl|  楼主 | 2023-7-7 17:23 | 只看该作者
xiaoqizi 发表于 2023-7-7 13:45
这种根据按键来进行操作的代码里边是不是需要添加防抖啊

对,要加

使用特权

评论回复
8
renzheshengui| | 2023-7-7 18:05 | 只看该作者
这个计数器有没有实际中的用处呢 还是就是用来练习计数器以及io的操作呢

使用特权

评论回复
9
wakayi| | 2023-7-7 18:37 | 只看该作者
清零的同时是停止计时还是从零开始继续计时呢

使用特权

评论回复
10
szt1993| | 2023-7-11 22:00 | 只看该作者
wakayi 发表于 2023-7-7 18:37
清零的同时是停止计时还是从零开始继续计时呢

楼主暂停和清0是分别控制的,清零后是暂停的,开始后才开始

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

715

帖子

9

粉丝