- void lcd_io_init()
- {
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);
- Gpio_SetAnalogMode(STK_LCD_COM0_PORT, STK_LCD_COM0_PIN); //COM0
- Gpio_SetAnalogMode(STK_LCD_COM1_PORT, STK_LCD_COM1_PIN); //COM1
- Gpio_SetAnalogMode(STK_LCD_COM2_PORT, STK_LCD_COM2_PIN); //COM2
- Gpio_SetAnalogMode(STK_LCD_COM3_PORT, STK_LCD_COM3_PIN); //COM3
- Gpio_SetAnalogMode(STK_LCD_SEG0_PORT, STK_LCD_SEG0_PIN); //SEG0
- Gpio_SetAnalogMode(STK_LCD_SEG1_PORT, STK_LCD_SEG1_PIN); //SEG1
- Gpio_SetAnalogMode(STK_LCD_SEG2_PORT, STK_LCD_SEG2_PIN); //SEG2
- Gpio_SetAnalogMode(STK_LCD_SEG3_PORT, STK_LCD_SEG3_PIN); //SEG3
- Gpio_SetAnalogMode(STK_LCD_SEG4_PORT, STK_LCD_SEG4_PIN); //SEG4
- Gpio_SetAnalogMode(STK_LCD_SEG5_PORT, STK_LCD_SEG5_PIN); //SEG5
- Gpio_SetAnalogMode(STK_LCD_SEG6_PORT, STK_LCD_SEG6_PIN); //SEG6
- Gpio_SetAnalogMode(STK_LCD_SEG7_PORT, STK_LCD_SEG7_PIN); //SEG7
- Gpio_SetAnalogMode(GpioPortB, GpioPin3); //VLCDH
- Gpio_SetAnalogMode(GpioPortB, GpioPin4); //VLCD3
- Gpio_SetAnalogMode(GpioPortB, GpioPin5); //VLCD2
- Gpio_SetAnalogMode(GpioPortB, GpioPin6); //VLCD1
- }
LCD模块使用低速时钟,因此要开启内部低速时钟或外部低速晶振
初始化LCD模块
- #define LCD_MODE 0
- void lcd_init()
- {
- stc_lcd_cfg_t LcdInitStruct;
- stc_lcd_segcom_t LcdSegCom;
-
- Sysctrl_ClkSourceEnable(SysctrlClkXTL,TRUE);
- Sysctrl_SetPeripheralGate(SysctrlPeripheralLcd,TRUE); ///< 开启LCD时钟
- LcdSegCom.u32Seg0_31 = 0xffffff00; ///< 配置LCD_POEN0寄存器 开启SEG0~SEG7
- LcdSegCom.stc_seg32_51_com0_8_t.seg32_51_com0_8 = 0xffffffff; ///< 初始化LCD_POEN1寄存器 全部关闭输出端口
- LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Com0_3 = 0; ///< 使能COM0~COM3
- LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Mux = 0; ///< Mux=0,Seg32_35=0,BSEL=1表示:选择外部电容工作模式,内部电阻断路
- LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Seg32_35 = 0;
- Lcd_SetSegCom(&LcdSegCom); ///< LCD COMSEG端口配置
- LcdInitStruct.LcdBiasSrc = LcdExtCap; ///< 电容分压模式,需要外部电路配合
- LcdInitStruct.LcdDuty = LcdDuty4; ///< 1/4duty
- LcdInitStruct.LcdBias = LcdBias3; ///< 1/3 BIAS
- LcdInitStruct.LcdCpClk = LcdClk2k; ///< 电压泵时钟频率选择2kHz
- LcdInitStruct.LcdScanClk = LcdClk128hz; ///< LCD扫描频率选择128Hz
- LcdInitStruct.LcdMode = LCD_MODE==0?LcdMode0:LcdMode1;
- LcdInitStruct.LcdClkSrc = LcdXTL; ///< LCD时钟选择XTL
- LcdInitStruct.LcdEn = LcdEnable; ///< 使能LCD模块
- Lcd_Init(&LcdInitStruct);
- }
来看看如何显示指定的数字,先找到这块屏的资料
在看看手册里是怎么控制的
模式0
模式1
显示代码
- #if(LCD_MODE == 0)
- uint32_t lcdrambuffer[2] = {0};
- #else
- uint8_t lcdrambuffer[4] = {0};
- #endif
- void lcdshow09num(uint8_t num,uint8_t pos)
- {
- if(pos > 3)
- return;
- #if(LCD_MODE == 0)
- uint32_t temp;
- switch(num)
- {
- case 0:
- temp = 0x0F05;
- break;
- case 1:
- temp = 0x0600;
- break;
- case 2:
- temp = 0x0B06;
- break;
- case 3:
- temp = 0x0F02;
- break;
- case 4:
- temp = 0x0603;
- break;
- case 5:
- temp = 0x0D03;
- break;
- case 6:
- temp = 0x0D07;
- break;
- case 7:
- temp = 0x0700;
- break;
- case 8:
- temp = 0x0F07;
- break;
- case 9:
- temp = 0x0F03;
- break;
- default:
- break;
-
- }
- switch(pos)
- {
- case 0:
- lcdrambuffer[0] &= 0xFFFF0008;
- lcdrambuffer[0] |= temp;
- Lcd_WriteRam(0,lcdrambuffer[0]);
- break;
- case 1:
- lcdrambuffer[0] &= 0x0008FFFF;
- lcdrambuffer[0] |= ((temp<<16)&0xFFFF0000);
- Lcd_WriteRam(0,lcdrambuffer[0]);
- break;
- case 2:
- lcdrambuffer[1] &= 0xFFFF0008;
- lcdrambuffer[1] |= temp;
- Lcd_WriteRam(1,lcdrambuffer[1]);
- break;
- case 3:
- lcdrambuffer[1] &= 0x0008FFFF;
- lcdrambuffer[1] |= ((temp<<16)&0xFFFF0000);
- Lcd_WriteRam(1,lcdrambuffer[1]);
- break;
- default:
- break;
- }
- #else
- uint8_t temp[4] = {0};
- switch(num)
- {
- case 0:
- temp[0] = 0x03;
- temp[1] = 0x02;
- temp[2] = 0x03;
- temp[3] = 0x02;
- break;
- case 1:
- temp[0] = 0x00;
- temp[1] = 0x02;
- temp[2] = 0x02;
- temp[3] = 0x00;
- break;
- case 2:
- temp[0] = 0x02;
- temp[1] = 0x03;
- temp[2] = 0x01;
- temp[3] = 0x02;
- break;
- case 3:
- temp[0] = 0x02;
- temp[1] = 0x03;
- temp[2] = 0x02;
- temp[3] = 0x02;
- break;
- case 4:
- temp[0] = 0x01;
- temp[1] = 0x03;
- temp[2] = 0x02;
- temp[3] = 0x00;
- break;
- case 5:
- temp[0] = 0x03;
- temp[1] = 0x01;
- temp[2] = 0x02;
- temp[3] = 0x02;
- break;
- case 6:
- temp[0] = 0x03;
- temp[1] = 0x01;
- temp[2] = 0x03;
- temp[3] = 0x02;
- break;
- case 7:
- temp[0] = 0x02;
- temp[1] = 0x02;
- temp[2] = 0x02;
- temp[3] = 0x00;
- break;
- case 8:
- temp[0] = 0x03;
- temp[1] = 0x03;
- temp[2] = 0x03;
- temp[3] = 0x02;
- break;
- case 9:
- temp[0] = 0x03;
- temp[1] = 0x03;
- temp[2] = 0x02;
- temp[3] = 0x02;
- break;
- default:
- break;
- }
- lcdrambuffer[0] &= ~(3<<(pos*2));
- lcdrambuffer[0] |= (temp[0]<<(pos*2));
- lcdrambuffer[1] &= ~(3<<(pos*2));
- lcdrambuffer[1] |= (temp[1]<<(pos*2));
- lcdrambuffer[2] &= ~(3<<(pos*2));
- lcdrambuffer[2] |= (temp[2]<<(pos*2));
- lcdrambuffer[3] &= ~(2<<(pos*2));
- lcdrambuffer[3] |= (temp[3]<<(pos*2));
- Lcd_WriteRam(0,lcdrambuffer[0]);
- Lcd_WriteRam(1,lcdrambuffer[1]);
- Lcd_WriteRam(2,lcdrambuffer[2]);
- Lcd_WriteRam(3,lcdrambuffer[3]);
- #endif
- }
- void lcdshowdot(uint8_t dotpos,uint8_t show)
- {
- if(dotpos > 3)
- return;
- #if(LCD_MODE == 0)
- switch(dotpos)
- {
- case 0:
- if(show > 0)
- lcdrambuffer[0] |= 0x00000008;
- else
- lcdrambuffer[0] &= 0xFFFFFFF7;
- Lcd_WriteRam(0,lcdrambuffer[0]);
- break;
- case 1:
- if(show > 0)
- lcdrambuffer[0] |= 0x00080000;
- else
- lcdrambuffer[0] &= 0xFFF7FFFF;
- Lcd_WriteRam(0,lcdrambuffer[0]);
- break;
- case 2:
- if(show > 0)
- lcdrambuffer[1] |= 0x00000008;
- else
- lcdrambuffer[1] &= 0xFFFFFFF7;
- Lcd_WriteRam(1,lcdrambuffer[1]);
- break;
- case 3:
- if(show > 0)
- lcdrambuffer[1] |= 0x00080000;
- else
- lcdrambuffer[1] &= 0xFFF7FFFF;
- Lcd_WriteRam(1,lcdrambuffer[1]);
- break;
- default:
- break;
- }
- #else
- if(show > 0)
- lcdrambuffer[3] |= (1<<(dotpos*2));
- else
- lcdrambuffer[3] &= ~(1<<(dotpos*2));
- Lcd_WriteRam(3,lcdrambuffer[3]);
- #endif
- }
timer0修改为10ms,中断处理
- uint16_t timecount = 0;
- uint8_t showseconddot = 1;
- uint8_t timerrun = 0;
- void Tim0_IRQHandler(void)
- {
- //Timer0 模式0 溢出中断
- if(TRUE == Bt_GetIntFlag(TIM0, BtUevIrq))
- {
- Bt_ClearIntFlag(TIM0,BtUevIrq); //中断标志清零
- if(timerrun == 1)
- {
- if(timecount < 9999)
- timecount += 1;
- else
- {
- timecount = 0;
- //Gpio_WriteOutputIO(STK_LED_PORT, STK_LED_PIN,!Gpio_ReadOutputIO(STK_LED_PORT, STK_LED_PIN));
- }
- lcdshow09num(timecount%10,3);
- lcdshow09num((timecount%100)/10,2);
- lcdshow09num((timecount%1000)/100,1);
- lcdshow09num(timecount/1000,0);
- if(timecount%50 == 0)
- {
- showseconddot = 1-showseconddot;
- lcdshowdot(1,showseconddot);
- }
- }
- }
- }
按键处理
- void PortA_IRQHandler(void)
- {
- if(TRUE == Gpio_GetIrqStatus(STK_USER_PORT, STK_USER_PIN))
- {
- if(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE)
- {
- if(timerrun == 0)
- {
- timecount = 0;
- showseconddot = 1;
- lcdshowdot(1,1);
- timerrun = 1;
- }
- else if(timerrun == 1)
- {
- timerrun = 2;
- }
- else
- {
- timerrun = 0;
- lcdshow09num(0,3);
- lcdshow09num(0,2);
- lcdshow09num(0,1);
- lcdshow09num(0,0);
- lcdshowdot(1,0);
- }
- }
- Gpio_ClearIrq(STK_USER_PORT, STK_USER_PIN);
- }
- }
运行效果
6.2WDT看门狗测试
WDT(Watch Dog Timer)看门狗定时器可用来检测和解决由软件错误引起的故障。当 WDT计数器达到设定的溢出时间后,会触发中断或产生系统复位,WDT由专用的10KHz片内振荡器驱动。
开启看门狗并配置好时间,看门狗复位模式
- void wdt_init()
- {
- Sysctrl_SetPeripheralGate(SysctrlPeripheralWdt,TRUE);
- Wdt_Init(WdtResetEn, WdtT1s64);
- Wdt_Start();
- }
LCD自动计数,在主循环中定时喂狗,按键按下阻塞住,超时后系统会复位,LCD计数从0开始
- int32_t main(void)
- {
- xth_init();
- //时钟分频设置
- Sysctrl_SetHCLKDiv(SysctrlHclkDiv1);
- Sysctrl_SetPCLKDiv(SysctrlPclkDiv1);
- led_init();
- key_init();
- timer0_init();
- lcd_io_init();
- lcd_init();
- Lcd_ClearDisp(); ///< 清屏
- lcdshowdot(2,1);
- timerrun = 0;
- lcdshow09num(0,3);
- lcdshow09num(0,2);
- lcdshow09num(0,1);
- lcdshow09num(0,0);
- lcdshowdot(1,0);
- wdt_init();
- while(1)
- {
- while(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE);
- Wdt_Feed();
- yuyy_delay_ms(1000);
- }
- }
运行效果
再试试看门狗中断
- void wdt_init()
- {
- Sysctrl_SetPeripheralGate(SysctrlPeripheralWdt,TRUE);
- Wdt_Init(WdtIntEn, WdtT1s64);
- EnableNvic(WDT_IRQn, IrqLevel3, TRUE);
- Wdt_Start();
- }
- void Wdt_IRQHandler(void)
- {
- if(Wdt_GetIrqStatus())
- {
- Wdt_IrqClr(); ///<清除 wdt 中断标记
- Gpio_WriteOutputIO(STK_LED_PORT, STK_LED_PIN,!Gpio_ReadOutputIO(STK_LED_PORT, STK_LED_PIN));
- }
- }
运行效果
6.3RTC测试
RTC(Real Time Clock)实时时钟提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整
接下来开启RTC,尝试用串口打印RTC的时间,开启RTC并初始化时间
- void rtc_init()
- {
- stc_rtc_initstruct_t RtcInitStruct;
- Sysctrl_SetPeripheralGate(SysctrlPeripheralRtc,TRUE);//RTC模块时钟打开
- RtcInitStruct.rtcAmpm = RtcPm; //24小时制
- RtcInitStruct.rtcClksrc = RtcClkXth1024; //外部32M晶振
- RtcInitStruct.rtcPrdsel.rtcPrdsel = RtcPrdx; //周期中断类型PRDX
- RtcInitStruct.rtcPrdsel.rtcPrdx = 1u; //周期中断时间间隔 1秒
- RtcInitStruct.rtcTime.u8Second = 0x55; //配置RTC时间
- RtcInitStruct.rtcTime.u8Minute = 0x01;
- RtcInitStruct.rtcTime.u8Hour = 0x09;
- RtcInitStruct.rtcTime.u8Day = 0x08;
- RtcInitStruct.rtcTime.u8DayOfWeek = 0x02;
- RtcInitStruct.rtcTime.u8Month = 0x08;
- RtcInitStruct.rtcTime.u8Year = 0x23;
- RtcInitStruct.rtcCompen = RtcCompenEnable; // 使能时钟误差补偿
- RtcInitStruct.rtcCompValue = 0; //补偿值 根据实际情况进行补偿
- Rtc_Init(&RtcInitStruct);
- Rtc_AlmIeCmd(TRUE); //使能闹钟中断
-
- EnableNvic(RTC_IRQn, IrqLevel3, TRUE); //使能RTC中断向量
- Rtc_Cmd(TRUE); //使能RTC开始计数
- }
RTC中断处理
- void print_rtc()
- {
- stc_rtc_time_t readtime;
- printf("RTC:%02X年%02X月%02X日 星期%02X %02X:%02X:%02X",readtime.u8Year,readtime.u8Month,readtime.u8Day,readtime.u8DayOfWeek,readtime.u8Hour,readtime.u8Minute,readtime.u8Second);
- }
- void Rtc_IRQHandler(void)
- {
- if(Rtc_GetPridItStatus() == TRUE)
- {
- Rtc_ClearPrdfItStatus(); //清除中断标志位
- print_rtc();
- }
- }
运行效果
串口修改时间
- void set_rtc()
- {
- if(uart_rxlen > 5)
- {
- stc_rtc_time_t settime;
- settime.u8Year = uart_buffer[0];
- settime.u8Month = uart_buffer[1];
- settime.u8Day = uart_buffer[2];
- settime.u8DayOfWeek = uart_buffer[3];
- settime.u8Hour = uart_buffer[4];
- settime.u8Minute = uart_buffer[5];
- settime.u8Second = uart_buffer[6];
- Rtc_SetTime(&settime);
- }
- uart_rxlen = 0;
- uart_rxindex = 0;
- }
- void uart_rxtimeout()
- {
- set_rtc();
- }
运行效果
用12864LCD做一个带日期显示的电子时钟
- void time_chars_init()
- {
- Spi_SetCS(M0P_SPI0, FALSE);
- yuyy_hs12864g18b_display_string_8x16(&hs12864_ctr,0,0,0,(uint8_t *)"HC32L196PCTA RTC");
- yuyy_hs12864g18b_display_string_8x16(&hs12864_ctr,0,6,0,(uint8_t *)"Code by yuyy1989");
- yuyy_hs12864g18b_display_graphic_16x16(&hs12864_ctr,0,2,16,(uint8_t *)time_chars[7]);
- yuyy_hs12864g18b_display_graphic_16x16(&hs12864_ctr,0,2,48,(uint8_t *)time_chars[8]);
- yuyy_hs12864g18b_display_graphic_16x16(&hs12864_ctr,0,2,80,(uint8_t *)time_chars[0]);
- yuyy_hs12864g18b_display_graphic_16x16(&hs12864_ctr,0,2,98,(uint8_t *)time_chars[9]);
- }
- void print_rtc()
- {
- char out[20];
- stc_rtc_time_t readtime;
- Rtc_ReadDateTime(&readtime);
- Spi_SetCS(M0P_SPI0, FALSE);
- sprintf(out,"%02X",readtime.u8Year);
- yuyy_hs12864g18b_display_string_8x16(&hs12864_ctr,0,2,0,(uint8_t *)out);
- sprintf(out,"%02X",readtime.u8Month);
- yuyy_hs12864g18b_display_string_8x16(&hs12864_ctr,0,2,32,(uint8_t *)out);
- sprintf(out,"%02X",readtime.u8Day);
- yuyy_hs12864g18b_display_string_8x16(&hs12864_ctr,0,2,64,(uint8_t *)out);
- yuyy_hs12864g18b_display_graphic_16x16(&hs12864_ctr,0,2,114,(uint8_t *)time_chars[readtime.u8DayOfWeek]);
- sprintf(out,"%02X:%02X:%02X",readtime.u8Hour,readtime.u8Minute,readtime.u8Second);
- yuyy_hs12864g18b_display_string_8x16(&hs12864_ctr,0,4,32,(uint8_t *)out);
- Spi_SetCS(M0P_SPI0, TRUE);
- }
运行效果
6.4FLASH测试
HC32L196内部集成了256K的flash,每块 FLASH 按照Sector进行划分,每个Sector容量为512字节
做个简单的程序测试一下,按下按键时生成一个0-9999的随机数,用段码LCD显示并存储到FLASH,系统初始化时读出存储的数字并放到LCD上显示
- #define FLASH_ADDR 0x1FE00
- void flash_init()
- {
- while(Ok != Flash_Init(8, TRUE))
- {
- while(1);
- }
- }
- void read_data_from_flash()
- {
- Flash_LockSet(FlashLock1, 0x80000000);
- while(Ok != Flash_OpModeConfig(FlashReadMode));
- testdata = *((unsigned short int *)FLASH_ADDR);
- Flash_LockAll();
- show_testdata();
- }
- void write_data_to_flash()
- {
- Flash_LockSet(FlashLock1, 0x80000000);
- while(Ok != Flash_OpModeConfig(FlashSectorEraseMode));
- if(Ok != Flash_SectorErase(FLASH_ADDR))
- {
- while(1);
- }
- ///< FLASH 字节写、校验
- while(Ok != Flash_OpModeConfig(FlashWriteMode));
- if (Ok != Flash_Write16(FLASH_ADDR, &testdata, 1))
- {
- while(1);
- }
- Flash_LockAll();
- }
按键按下生成随机数并保存- void PortA_IRQHandler(void)
- {
- if(TRUE == Gpio_GetIrqStatus(STK_USER_PORT, STK_USER_PIN))
- {
- Gpio_ClearIrq(STK_USER_PORT, STK_USER_PIN);
- if(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE)
- {
- Gpio_WriteOutputIO(STK_LED_PORT, STK_LED_PIN,!Gpio_ReadOutputIO(STK_LED_PORT, STK_LED_PIN));
- Trng_Generate();
- testdata = Trng_GetData0()%10000;
- show_testdata();
- write_data_to_flash();
- }
- }
- }
运行效果