原理
CH32V203 驱动代码
#include "LED188Display.h" #include "SysTick.h" #include "Utils.h" #include <strings.h> #include <assert.h> const GPIOSpeed_TypeDef GPIO_Speed = GPIO_Speed_2MHz; typedef struct _SEGPOINT{ GPIO_TypeDef* PORT; uint16_t PIN; } SEGPOINT; #define DPA {GPIOB,GPIO_Pin_3} #define DPB {GPIOB,GPIO_Pin_4} #define DPC {GPIOB,GPIO_Pin_5} #define DPD {GPIOB,GPIO_Pin_6} #define DPE {GPIOB,GPIO_Pin_7} //显示五个针脚 const SEGPOINT POINTS[] = {DPA, DPB, DPC, DPD, DPE}; //定义显示表,5针,可以显示 5*4=20 种状态 i=j 不能用 u8 showTable[5][5] = {0}; const u16 LEDPins = POINTS[0].PIN | POINTS[1].PIN | POINTS[2].PIN | POINTS[3].PIN | POINTS[4].PIN; volatile static uint8_t value = 0; volatile static uint8_t k1 = 0; volatile static uint8_t k2 = 0; volatile static u8 needUpdate = 0; volatile static uint8_t blink = 0; static uint32_t _counter = 0; void updateTable(uint8_t num, uint8_t fan, uint8_t zhilen); void display(void){ // uint8_t num = value; if(blink){ _counter++; if(_counter > 55){ _counter = 0; } } else{ _counter = 0; } if(needUpdate){ needUpdate = 0; updateTable(value, k1, k2); } for(u8 i = 0; i < 5; i++){ //个位闪烁时熄灭状态 if(_counter >= 30 && i == 0) continue; //判断第i个PIN 为低电平时,有需要显示me v为0 不需要显示, 其他需要显示 u8 v = showTable[i][1] | showTable[i][2] | showTable[i][3] | showTable[i][4]; if(_counter < 30){ v |= showTable[i][0]; } //第 0 位闪烁时, 不亮 LED 不需要参加判断 if(v){ //第 i个引脚为低电平时, 其他4 个引脚 有至少一个 段要亮, 所以需要设置第 i 个引脚为低电平 GPIO_ResetBits(POINTS[i].PORT, POINTS[i].PIN); u8 highPins = 0;//记录需要高电平的引脚 //判断其他 4 个引脚 是否有需要显示的段,需要就要设置为高电平 for(u8 j = 0; j < 5; j++){ if(j == i || showTable[i][j] == 0)continue; if((j == 0 || i == 0) && _counter >= 30) continue; //如果 i 和 j 都不是 0,或者 _counter < 30,才设置 highPins if((i != 0 && j != 0) || _counter < 30){ highPins |= POINTS[j].PIN; } } //设置highPins为高电平 GPIO_CONFIG(POINTS[i].PORT, highPins, GPIO_Mode_Out_PP, GPIO_Speed); GPIO_SetBits(POINTS[i].PORT, highPins); //延时 Delay_US(50); //设置highPins为高阻状态, 这些 PIN 已经是高电平了.一行代码搞定 GPIO_CONFIG(GPIOB, highPins, GPIO_Mode_Out_OD, GPIO_Speed); //恢复低电平PIN为高阻状态 GPIO_SetBits(POINTS[i].PORT, POINTS[i].PIN); } } } //根据段码表得到,不能修改 #define FAN_SEG_CODE 0x02 #define COOL_SEG_CODE 0x04 /* 0-9 的段码, 0x01 代表 风扇, 0x02 代表制冷 */ u8 segmentCodes[] = {0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B, FAN_SEG_CODE, COOL_SEG_CODE}; typedef struct{ u8 pH; u8 pL; }AK; #define _NCAK {0,0} //没有用的 AK const AK AKTable[3][7] = { {{4, 0}, {3, 0}, {0, 3}, {2, 0}, {0, 2}, {1, 0}, {0, 1}},//个位 {{4, 3}, {4, 2}, {4, 1}, {3, 1}, {3, 2}, {2, 1}, {1, 2}},//十位 {_NCAK, {2, 4}, {1, 4}, _NCAK, {1, 3}, {2, 3}, _NCAK},//百位和风扇图标,制冷图标 }; void getTableIndex(u8 wei, u8 mask, u8* pH, u8* pL) { u8 bit = __builtin_ctz(mask); // u8 bit; // __asm__("ctz %0, %1" : "=r"(bit) : "r"(mask)); AK ak = AKTable[wei][bit]; *pH = ak.pH; *pL = ak.pL; } void updateTable(uint8_t num, uint8_t fan, uint8_t zhilen){ bzero(showTable, sizeof(showTable)); u8 pH = 0;//高位PIN在POINTS中的索引 u8 pL = 0;//低位PIN在POINTS中的索引 u8 code = 0;//当前位段码 u8 value = num; //个,十,百位, 风扇, 制冷图标编码在百位F2,E2中 for(u8 j = 0; j < 3; j++){ code = segmentCodes[value % 10]; u8 mask = 1; for(u8 i = 0; i < 7; i++){ u8 v = code & mask; if(v){ getTableIndex(j, mask, &pH, &pL); showTable[pL][pH] = mask; } mask <<= 1; } value /= 10; if(value <= 0) break; } if(fan){ getTableIndex(2, FAN_SEG_CODE, &pH, &pL); showTable[pL][pH] = FAN_SEG_CODE; } if(zhilen){ getTableIndex(2, COOL_SEG_CODE, &pH, &pL); showTable[pL][pH] = COOL_SEG_CODE; } } void LED188_Display(uint8_t num, uint8_t fan, uint8_t zhilen, uint8_t b){ if(num > 199){ num = 199; } if(value == num && fan == k1 && zhilen == k2 && blink == b)return; value = num; k1 = fan; k2 = zhilen; blink = b; needUpdate = 1; }