原理
CH32V203 驱动代码
C
#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;
}