MS-DTU/Anjiehui7_TTS_ST_V2.4_LOCAL/User/Lcd_drv.c

447 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 > 36)
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();
}
}