#include "includes.h" // 是否自检屏状态 u8 self_check_state = 0; // 显示缓冲区 TVideoBuf VideoBuf = {0}; TVideoBuf Last_VideoBuf = {0}; // 定义7段字库编码 // |-A-| // F B // |-G-| // E C // |-D-| typedef struct { unsigned A : 1; unsigned B : 1; unsigned C : 1; unsigned D : 1; unsigned E : 1; unsigned F : 1; unsigned G : 1; unsigned : 1; } TChar; // 字库,不带小数点或单位 const TChar CLib[] = { {0, 0, 0, 0, 0, 0, 0}, // ' ' {0, 0, 0, 0, 0, 0, 1}, // '-' {0, 1, 1, 0, 0, 0, 1}, // '+' = '-|' {1, 0, 0, 0, 0, 0, 0}, // '^' {1, 1, 1, 0, 1, 1, 1}, // 'A' {0, 0, 1, 1, 1, 1, 1}, // 'b' {0, 0, 0, 1, 1, 0, 1}, // 'c' {0, 1, 1, 1, 1, 0, 1}, // 'd' {1, 0, 0, 1, 1, 1, 1}, // 'E' {1, 0, 0, 0, 1, 1, 1}, // 'F' {1, 0, 1, 1, 1, 1, 0}, // 'G' {0, 0, 1, 0, 1, 1, 1}, // 'h' {0, 0, 0, 0, 1, 1, 0}, // 'I' {0, 1, 1, 1, 0, 0, 0}, // 'J' {0, 0, 0, 1, 0, 0, 0}, // 'K' = '_' {0, 0, 0, 1, 1, 1, 0}, // 'L' {0, 0, 0, 1, 0, 0, 0}, // 'M' = '_' {0, 0, 1, 0, 1, 0, 1}, // 'n' {0, 0, 1, 1, 1, 0, 1}, // 'o' {1, 1, 0, 0, 1, 1, 1}, // 'P' {1, 1, 1, 0, 0, 1, 1}, // 'q' {0, 0, 0, 0, 1, 0, 1}, // 'r' {1, 0, 1, 1, 0, 1, 1}, // 'S' {0, 0, 1, 0, 0, 0, 1}, // 't' {0, 1, 1, 1, 1, 1, 0}, // 'U' {0, 1, 0, 0, 1, 1, 1}, // 'V' {0, 0, 0, 1, 0, 0, 0}, // 'W' = '_' {0, 0, 0, 1, 0, 0, 0}, // 'X' = '_' {0, 1, 1, 1, 0, 1, 1}, // 'y' {0, 0, 0, 1, 0, 0, 0}, // 'Z' = '_' {1, 1, 1, 1, 1, 1, 0}, // '0' {0, 1, 1, 0, 0, 0, 0}, // '1' {1, 1, 0, 1, 1, 0, 1}, // '2' {1, 1, 1, 1, 0, 0, 1}, // '3' {0, 1, 1, 0, 0, 1, 1}, // '4' {1, 0, 1, 1, 0, 1, 1}, // '5' {1, 0, 1, 1, 1, 1, 1}, // '6' {1, 1, 1, 0, 0, 0, 0}, // '7' {1, 1, 1, 1, 1, 1, 1}, // '8' {1, 1, 1, 1, 0, 1, 1}, // '9' }; // 字符在字库中的编码 typedef enum { CODE_SPACE, CODE_MINUS, CODE_PLUS, CODE_EXP, CODE_A, CODE_B, CODE_C, CODE_D, CODE_E, CODE_F, CODE_G, CODE_H, CODE_I, CODE_J, CODE_K, CODE_L, CODE_M, CODE_N, CODE_O, CODE_P, CODE_Q, CODE_R, CODE_S, CODE_T, CODE_U, CODE_V, CODE_W, CODE_X, CODE_Y, CODE_Z, CODE_0, CODE_1, CODE_2, CODE_3, CODE_4, CODE_5, CODE_6, CODE_7, CODE_8, CODE_9 } TCode; TCode HT1621_Char2Code(char c) { if(c >= '0' && c <= '9') return CODE_0 + (c - '0'); if(c >= 'a' && c <= 'z') return CODE_A + (c - 'a'); if(c >= 'A' && c <= 'Z') return CODE_A + (c - 'A'); if(c == '-') return CODE_MINUS; if(c == '+') return CODE_PLUS; if(c == '^') return CODE_EXP; return CODE_SPACE; } // pin_no: 1~41 // com_no: 1~4 void HT1621_WriteBuf(u16 pin_com, u8 bit_val) { uint8_t byte_index, bit_index; uint8_t pin_no = pin_com / 10; uint8_t com_no = pin_com % 10; if(pin_no < 1 || pin_no > 41) return; if(com_no < 1 || com_no > 4) return; byte_index = (pin_no - 1) / 2; bit_index = com_no - 1; // COM4高位,COM1低位 if((pin_no - 1) % 2) bit_index += 4; // 奇数pin高4位,偶数pin低4位 if(bit_val) VideoBuf.buf[byte_index] |= (1 << bit_index); else VideoBuf.buf[byte_index] &= ~(1 << bit_index); } // 写一个七段码字符 // pin_comA = (A段的pin_no) * 10 + (A段的com_no) void HT1621_WriteChar(char c, u16 pin_comA, u16 pin_comB, u16 pin_comC, u16 pin_comD, u16 pin_comE, u16 pin_comF, u16 pin_comG) { TCode code = HT1621_Char2Code(c); HT1621_WriteBuf(pin_comA, CLib[code].A); HT1621_WriteBuf(pin_comB, CLib[code].B); HT1621_WriteBuf(pin_comC, CLib[code].C); HT1621_WriteBuf(pin_comD, CLib[code].D); HT1621_WriteBuf(pin_comE, CLib[code].E); HT1621_WriteBuf(pin_comF, CLib[code].F); HT1621_WriteBuf(pin_comG, CLib[code].G); } // 写一个七段码数据 // pin_comA = (A段的pin_no) * 10 + (A段的com_no) void HT1621_Write7Seg(u8 val, u16 pin_comA, u16 pin_comB, u16 pin_comC, u16 pin_comD, u16 pin_comE, u16 pin_comF, u16 pin_comG) { HT1621_WriteBuf(pin_comA, val & 1); val >>= 1; HT1621_WriteBuf(pin_comB, val & 1); val >>= 1; HT1621_WriteBuf(pin_comC, val & 1); val >>= 1; HT1621_WriteBuf(pin_comD, val & 1); val >>= 1; HT1621_WriteBuf(pin_comE, val & 1); val >>= 1; HT1621_WriteBuf(pin_comF, val & 1); val >>= 1; HT1621_WriteBuf(pin_comG, val & 1); } /////////////////////////////////////////////////////////////////////////////////// // 以下定义适用于HT16C23驱动芯片 #define HT16C23_ADDR (0x7C) // 0111110(r/w) //命令 #define WRITE_LCD 0x80 #define DRIVE_MODE_CMD 0x82 #define SYS_MODE_CMD 0x84 #define FRQ_CMD 0x86 #define BLINK_FRQ_CMD 0x88 #define VOL_SET_CMD 0x8a //参数定义 #define BIAS_LCD 0x00 // 驱动模式 SEG55*4com显示段位模式 1/4duty 1/3bias #define SYS_MODE_LCD 0x03 //显示和内部晶振都打开 #define FRQ_LCD 0x00 //0--80HZ 1--160HZ #define BLINK_FRQ_LCD 0x00 //blinking off #define VOL_LCD 0x30 //1--内部V 电压3.3v /////////////////////////////////////////////////////////////////////////////////// // I2C写数据 uint8_t I2C_WriteBytes(uint8_t len, uint8_t *buf) { uint8_t idx = 0; uint8_t try_count = 2; int32_t loop; // I2C不允许打断。 __disable_irq(); do { idx = 0; LL_I2C_HandleTransfer(I2C1, HT16C23_ADDR, LL_I2C_ADDRSLAVE_7BIT, len, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE); // 发送数据 loop = 3000; while(!LL_I2C_IsActiveFlag_STOP(I2C1) && idx < len && loop > 0) { if(LL_I2C_IsActiveFlag_TXIS(I2C1)) LL_I2C_TransmitData8(I2C1, buf[idx++]); loop--; } LL_I2C_ClearFlag_STOP(I2C1); } while((--try_count) && idx < len); __enable_irq(); return (idx == len); } // 写命令 void HT1621_Cmd(u8 cmd, u8 val) { uint8_t buf[2] = {cmd, val}; I2C_WriteBytes(2, buf); } // 设置参数 void HT1621_SetParams() { HT1621_Cmd(DRIVE_MODE_CMD, BIAS_LCD); HT1621_Cmd(VOL_SET_CMD, VOL_LCD); //使用内部振荡器 HT1621_Cmd(FRQ_CMD, FRQ_LCD); HT1621_Cmd(BLINK_FRQ_CMD, BLINK_FRQ_LCD); HT1621_Cmd(SYS_MODE_CMD, SYS_MODE_LCD); } // 刷新整个显示屏内容 void HT1621_Refresh() { u8 i; // 每次刷新都设置参数(有一定几率参数丢失导致熄屏) HT1621_SetParams(); // 写显示数据命令 VideoBuf.cmd = WRITE_LCD; VideoBuf.addr = 0; // 比较显示内容和标志位,如无改变则不操作 if(memcmp(&VideoBuf, &Last_VideoBuf, sizeof(VideoBuf)) == 0) return; // 保存显示内容和标志位 Last_VideoBuf = VideoBuf; // 处理闪烁,根据标志位临时改变显示内容 if(!self_check_state && !VideoBuf.blink_visible) { // 隐藏数字(显示界面) if(VideoBuf.fld1_blink) // 显示1 { Disp_Fld1Text(" "); Disp_Fld1PointOff(); } if(VideoBuf.fld2_blink) // 显示2 { Disp_Fld2Text(" "); Disp_Fld2PointOff(); } if(VideoBuf.fld3_blink) // 显示3 { Disp_Fld3Text(" "); Disp_Fld3PointOff(); } if(VideoBuf.fld4_blink) // 显示4 { Disp_Fld4Text(" "); Disp_Fld4PointOff(); } if(VideoBuf.battery_blink) // 电池 Disp_WriteBattery(0); // 光标闪烁(配置界面) for(i = 0; i < VideoBuf.cursor_width; i++) Disp_DispChar(VideoBuf.cursor_pos + i, ' '); } // 写命令和数据 I2C_WriteBytes(2 + sizeof(VideoBuf.buf), &VideoBuf.cmd); // 恢复显示内容和标志位 VideoBuf = Last_VideoBuf; } // 整个屏幕全熄灭 void HT1621_AllOff() { self_check_state = 1; memset(VideoBuf.buf, 0x00, sizeof(VideoBuf.buf)); // 不影响最后的状态 HT1621_Refresh(); self_check_state = 0; } // 整个屏幕全点亮 void HT1621_AllOn() { self_check_state = 1; memset(VideoBuf.buf, 0xFF, sizeof(VideoBuf.buf)); // 不影响最后的状态 HT1621_Refresh(); self_check_state = 0; } void LCD_Init() { LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); /**I2C1 GPIO Configuration PB8 ------> I2C1_SCL PB9 ------> I2C1_SDA */ GPIO_InitStruct.Pin = LL_GPIO_PIN_8|LL_GPIO_PIN_9; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; GPIO_InitStruct.Alternate = LL_GPIO_AF_4; LL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void LCD_MyOpen() { LL_I2C_InitTypeDef I2C_InitStruct = {0}; /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); /** I2C Initialization */ LL_I2C_EnableAutoEndMode(I2C1); LL_I2C_DisableOwnAddress2(I2C1); LL_I2C_DisableGeneralCall(I2C1); LL_I2C_EnableClockStretching(I2C1); I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; I2C_InitStruct.Timing = 0x00503D5A; I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; I2C_InitStruct.DigitalFilter = 0; I2C_InitStruct.OwnAddress1 = 0; I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; LL_I2C_Init(I2C1, &I2C_InitStruct); LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); LL_I2C_Enable(I2C1); } // 熄屏 void HT1621_ScreenOff() { // 内部振荡器off,显示off HT1621_Cmd(SYS_MODE_CMD, 0); } // 任务主体 void Lcd_Task(void *p_arg) { static uint32_t halfSeconds = 0; uint16_t interval; uint8_t key; delay_ms(10); while(1) { // 等待信号量 xSemaphoreTake(Key_Semaphore, 500); // 喂狗 Watchdog_Feed(); // 判断防过充电磁阀动作是否超时 if(dcBuff.configDisplay.op_ANTI_OVERFILL && !dcBuff.configDisplay.op_ANTI_SINGLE_CTRL && IS_CHARGE_ENABLE_HIGH() && IsTickOut(Charge_Pulse_Time)) { KZ_CHARGE_ENABLE_LOW(); } if(IS_CHARGE_DISABLE_HIGH() && IsTickOut(Charge_Pulse_Time)) KZ_CHARGE_DISABLE_LOW(); // 判断常开电磁阀闭合是否超时 if(dcBuff.configDisplay.op_ANTI_NORM_OPEN && !IS_NORM_OPEN_ENABLED() && IsTickOut(Anti_Pulse_Time)) { KZ_NORM_OPEN_ENABLE(); } // 判断GPS定位是否超时 if(GPS_Waiting && IsTickOut(GPS_waitTick)) GPS_Waiting = 0; // 判断是否发送GPS数据 if(IsTickOut(GPS_tranTick)) { GPS_tranTick = GetDelayTick(dcBuff.configData.intervalGPSTrans * 1000); DTU_semGPS = 1; } // 默认刷屏周期 interval = 30; if(MeterInSamplePage() && interval > 3) interval = 3; if(dcBuff.configDisplay.op_ANTI_OVERFILL && Charge_Enabled && interval > 10) interval = 10; if(Manual_Charing && interval > 10) interval = 10; if(dcBuff.configDisplay.op_ALARM_OUTPUT && interval > 10) interval = 10; if(dcBuff.configDisplay.op_ANTI_NORM_OPEN && Anti_Enabled && interval > 10) interval = 10; // 有外供电,刷新频率提高到5秒 if(VCC_POWER_STATUS() && (!dcBuff.configDisplay.op_USE_SOLAR || dcBuff.dtuData.batVoltage > 4500) && interval > 5) interval = 5; // 有外供电,且1秒钟采集,刷新频率提高到1秒 if(VCC_POWER_STATUS() && (!dcBuff.configDisplay.op_USE_SOLAR || dcBuff.dtuData.batVoltage > 4500) && dcBuff.configDisplay.op_LOCAL_DISP_1S && interval > 1) interval = 1; // 判断是否采集数据 if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && ++halfSeconds >= interval * 2) { // 定时采集 halfSeconds = 0; // 发送消息给任务 Sample_Notify(); } // 处理按键 while(LoopBuff_GetCount(&Key_TaskM) > 0) { // 取出按键 memmove(&key, LoopBuff_GetDataPtr(&Key_TaskM, Key_TaskM.info.rdPtr), 1); LoopBuff_RemoveItems(&Key_TaskM, 1); // 处理按键 Form_OnKey(key); } // 刷新显示 Form_OnTimer(); } }