【上海航芯 ACM32F070开发板+触控功能评估板】03.不一样的LCD显示实现方式
[复制链接]
ACM32F070系列MCU带有一个段式LCD液晶显示控制器,最多支持8个公用端子(COM)和40个区段端子(SEG),可以驱动160(4*40)或者288(8*36)个LCD段位显示。主要特性如下:
高度灵活的帧速率控制
支持静态、 1/2、 1/3、 1/4、 1/6 和 1/8 占空比
支持 1/2、 1/3、 1/4 偏置
多达 16 个寄存器的 LCD 数据 RAM
可通过软件配置 LCD 的对比度
支持 A 类、 B 类波形
2 种驱动波形生成方式
- 内部电阻分压、外部电阻分压
- 可选的滤波电容
- 可通过软件配置内部电阻分压方式的功耗,从而匹配 LCD 面板所需的电容电荷
支持低功耗模式: LCD 控制器可在 Active、 Sleep、 Stop 模式下进行显示
可配置帧中断
支持 LCD 闪烁功能且可配置多种闪烁频率
未使用的 LCD 区段和公共引脚可配置为数字或模拟功能
官方程序中提供了LCD_TK的示例程序,对于LCD的实现部分支持了3款液晶显示屏,我们拿到手的开发上自带液晶屏型号为:YR1618A,对于液晶屏底层显示驱动,官方的示例程序定义很多的宏,然后通过对这些宏定义来封装函数实现功能,看了半天的官方示例程序,也就看懂他的编程想法,具体的宏定义需要一个一个对照LCD的真值表与MCU的连接方式去修改,如果再切换一个屏的时候,修改的内容和工作量想想就有点退缩了,所以在这边介绍和推荐我常用的一套LCD实现方式:通过查表、映射的方式来实现LCD的显示功能。
此方法程序更具有可读性、移植方便、兼容性强、实现的功能根据显示需要可作灵活调整……具体的我们需要准备如下几部分:
1、对于8段组合显示的内容,我们穷举了可以显示的所有字符,我们可以通过查表的方式,获取到这些显示字符对应的A~G段的显示状态;
2、对照LCD真值表,将LCD引脚与MCU引脚的硬件连接关系映射成一个表格,通过这个表格我们可以方便的查找到需要显示的段位所对应的COM和SEG下标
3、通过COM和SEG下标去操作MCU内LCD的显示缓存寄存器,将显示内容体现的屏幕上
具体的代码实现如下所示:
const LCD_CODING_TypeDef LCD_CODE_Table[38] =
{
{' ', 0x00},
{'0', 0x3F},
{'1', 0x06},
{'2', 0x5B},
{'3', 0x4F},
{'4', 0x66},
{'5', 0x6D},
{'6', 0x7D},
{'7', 0x07},
{'8', 0x7F},
{'9', 0x6F},
{'A', 0x77},
{'b', 0x7C},
{'c', 0x58},
{'C', 0x39},
{'d', 0x5E},
{'E', 0x79},
{'F', 0x71},
{'g', 0x6F},
{'H', 0x76},
{'h', 0x74},
{'i', 0x04},
{'I', 0x30},
{'J', 0x1E},
{'l', 0x30},
{'L', 0x38},
{'n', 0x54},
{'o', 0x5C},
{'O', 0x3F},
{'P', 0x73},
{'q', 0x67},
{'r', 0x50},
{'S', 0x6D},
{'t', 0x78},
{'u', 0x1C},
{'U', 0x3E},
{'y', 0x6E},
{'-', 0x40},
};
const char LCD_NAME_Table[LCD_COM_NUMBER][LCD_SEG_NUMBER][4] =
{
{"1A ", "1B ", "2A ", "2B ", "3A ", "3B ", "4A ", "4B ", "S9 ", "S10", "---", "---", "---", "7B ", "5B ", "5A ", "---", "---", "---", "7A ", "---", "---", "6A ", "6B ", "S1 ", "8A ", "8B ", "S14", "---", "---", "---", "---"},
{"1F ", "1G ", "2F ", "2G ", "3F ", "3G ", "4F ", "4G ", "S8 ", "S11", "---", "---", "---", "7G ", "5G ", "5F ", "---", "---", "---", "7F ", "---", "---", "6F ", "6G ", "S2 ", "8F ", "8G ", "S16", "---", "---", "---", "---"},
{"1E ", "1C ", "2E ", "2C ", "3E ", "3C ", "4E ", "4C ", "S7 ", "S12", "---", "---", "---", "7C ", "5C ", "5E ", "---", "---", "---", "7E ", "---", "---", "6E ", "6C ", "S3 ", "8E ", "8C ", "S15", "---", "---", "---", "---"},
{"1D ", "1P ", "2D ", "2P ", "3D ", "3P ", "4D ", "L1 ", "S6 ", "S5 ", "---", "---", "---", "7P ", "5P ", "5D ", "---", "---", "---", "7D ", "---", "---", "6D ", "6P ", "S4 ", "8D ", "L2 ", "S13", "---", "---", "---", "---"},
};
/*******************************************************************************
* [url=home.php?mod=space&uid=159083]@brief[/url] * @param
* @retval
* [url=home.php?mod=space&uid=1020061]@attention[/url] *******************************************************************************/
void LCD_WriteBit(uint8_t COMn, uint8_t SEGn, uint8_t State)
{
if(State) LCD_Buffer[COMn] |= (0x00000001 << SEGn);
else LCD_Buffer[COMn] &= ~(0x00000001 << SEGn);
HAL_LCD_Write(&LCD_Handle, COMn, LCD_Buffer[COMn]);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
uint8_t LCD_SearchCode(char ch)
{
for(uint8_t i = 0; i < 38; i++)
{
if(ch == LCD_CODE_Table[i].ch)
{
return LCD_CODE_Table[i].Data;
}
}
return 0xFF;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_SearchName(char *str, uint8_t *COMn, uint8_t *SEGn)
{
for(uint8_t i = 0; i < LCD_COM_NUMBER; i++)
{
for(uint8_t j = 0; j < LCD_SEG_NUMBER; j++)
{
if(strcmp(str, LCD_NAME_Table[i][j]) == 0)
{
*COMn = i; *SEGn = j; return;
}
}
}
*COMn = 0xFF;
*SEGn = 0xFF;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_Init(void)
{
GPIO_InitTypeDef GPIOx_Handle;
LCD_InResInitTypeDef LCD_InRes;
LCD_SegComInitTypeDef LCD_SegCom;
memset(&LCD_Handle, 0, sizeof(LCD_Handle));
LCD_Handle.Instance = LCD;
LCD_Handle.Init.Bias = LCD_BIAS_1_3;
LCD_Handle.Init.Duty = LCD_DUTY_1_4;
LCD_Handle.Init.DisplayMode = LCD_DisplayMode_1;
LCD_Handle.Init.LCDFrequency = LCD_LCDFrequency_512HZ;
LCD_Handle.Init.Driving_Waveform = LCD_Driving_Waveform_B;
LCD_Handle.Init.BiasSrc = LCD_BiasSrc_InRes_Seg31_35_Normal; //内部电阻模式
// LCD_Handle.Init.BlinkEN = LCD_BlinkEN_Enable; //闪频使能
LCD_Handle.Init.BlinkFrequency = 0x3; //帧间隔时间,影响帧中断时间和LCD DMA请求时间 以及闪烁时间
HAL_LCD_Init(&LCD_Handle);
memset(&LCD_InRes, 0, sizeof(LCD_InRes));
LCD_InRes.Contrast = LCD_Contrast_903VDD;
LCD_InRes.BiasRes = LCD_BiasRes_240k;
LCD_InRes.FastCharge = LCD_FastCharge_Enable;
LCD_InRes.PONTime = 0x3F;
LCD_InRes.DriveMod = LCD_DriveMod_FC;
HAL_LCD_InResConfig(&LCD_Handle, &LCD_InRes);
LCD_SegCom.SEG0_31 = 0xF0371C00;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEG32_39_COM0_8 = 0xFFFFFFFF;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEGCOM_bit.COM0_3 = 0;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEGCOM_bit.SEG32_35 = 0xF;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEGCOM_bit.SEG36_COM7 = 1;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEGCOM_bit.SEG37_COM6 = 1;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEGCOM_bit.SEG38_COM5 = 1;
LCD_SegCom.Stc_SEG32_39_COM0_8.SEGCOM_bit.SEG39_COM4 = 1;
HAL_LCD_SegComConfig(&LCD_Handle, &LCD_SegCom);
memset(&GPIOx_Handle, 0, sizeof(GPIOx_Handle));
GPIOx_Handle.Pin = GPIO_PIN_0 | GPIO_PIN_4 | GPIO_PIN_8 |
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |
GPIO_PIN_12;
GPIOx_Handle.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIOx_Handle);
GPIOx_Handle.Pin = GPIO_PIN_0 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIOx_Handle.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOB, &GPIOx_Handle);
GPIOx_Handle.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 |
GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |
GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |
GPIO_PIN_9;
GPIOx_Handle.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIOx_Handle);
GPIOx_Handle.Pin = GPIO_PIN_5;
GPIOx_Handle.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOD, &GPIOx_Handle);
GPIOx_Handle.Pin = GPIO_PIN_5;
GPIOx_Handle.Mode = GPIO_MODE_OUTPUT_PP;
GPIOx_Handle.Pull = GPIO_NOPULL;
GPIOx_Handle.Alternate = GPIO_FUNCTION_0;
HAL_GPIO_Init(GPIOA, &GPIOx_Handle);
GPIOx_Handle.Pin = GPIO_PIN_15;
GPIOx_Handle.Mode = GPIO_MODE_INPUT;
GPIOx_Handle.Pull = GPIO_PULLUP;
GPIOx_Handle.Alternate = GPIO_FUNCTION_0;
HAL_GPIO_Init(GPIOC, &GPIOx_Handle);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
MultiTimerStart(&LCD_MultiTimer, 100, LCD_MultiTimerCallback, "LCD");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_IRQHandler(void)
{
HAL_LCD_IRQHandler(&LCD_Handle);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_DisplayNumber1(uint8_t Index, char ch, uint8_t Point)
{
char TAB[4][8][4] =
{
{"1A ", "1B ", "1C ", "1D ", "1E ", "1F ", "1G ", "1P "},
{"2A ", "2B ", "2C ", "2D ", "2E ", "2F ", "2G ", "2P "},
{"3A ", "3B ", "3C ", "3D ", "3E ", "3F ", "3G ", "3P "},
{"4A ", "4B ", "4C ", "4D ", "4E ", "4F ", "4G ", "---"},
};
uint8_t COMn = 0xFF, SEGn = 0xFF;
uint8_t Code = LCD_SearchCode(ch);
if(Code != 0xFF)
{
for(uint8_t i = 0; i < 7; i++)
{
LCD_SearchName(TAB[Index][i], &COMn, &SEGn);
if((COMn != 0xFF) && (SEGn != 0xFF))
{
LCD_WriteBit(COMn, SEGn, (Code >> i) & 0x01);
}
}
LCD_SearchName(TAB[Index][7], &COMn, &SEGn);
if((COMn != 0xFF) && (SEGn != 0xFF))
{
LCD_WriteBit(COMn, SEGn, Point);
}
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_DisplayNumber2(uint8_t Index, char ch, uint8_t Point)
{
char TAB[4][8][4] =
{
{"5A ", "5B ", "5C ", "5D ", "5E ", "5F ", "5G ", "5P "},
{"6A ", "6B ", "6C ", "6D ", "6E ", "6F ", "6G ", "6P "},
{"7A ", "7B ", "7C ", "7D ", "7E ", "7F ", "7G ", "7P "},
{"8A ", "8B ", "8C ", "8D ", "8E ", "8F ", "8G ", "---"},
};
uint8_t COMn = 0xFF, SEGn = 0xFF;
uint8_t Code = LCD_SearchCode(ch);
if(Code != 0xFF)
{
for(uint8_t i = 0; i < 7; i++)
{
LCD_SearchName(TAB[Index][i], &COMn, &SEGn);
if((COMn != 0xFF) && (SEGn != 0xFF))
{
LCD_WriteBit(COMn, SEGn, (Code >> i) & 0x01);
}
}
LCD_SearchName(TAB[Index][7], &COMn, &SEGn);
if((COMn != 0xFF) && (SEGn != 0xFF))
{
LCD_WriteBit(COMn, SEGn, Point);
}
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_MultiTimerCallback(MultiTimer *timer, void *userData)
{
static uint32_t Number1 = 0;
static uint32_t Number2 = 0;
Number1 = (Number1 + 1) % 10000;
if(Number1 < 10)
{
LCD_DisplayNumber1(0, ' ', 0);
LCD_DisplayNumber1(1, ' ', 0);
LCD_DisplayNumber1(2, '0', 1);
LCD_DisplayNumber1(3, '0' + Number1, 0);
}
else if(Number1 < 100)
{
LCD_DisplayNumber1(0, ' ', 0);
LCD_DisplayNumber1(1, ' ', 0);
LCD_DisplayNumber1(2, '0' + ((Number1 / 10) % 10), 1);
LCD_DisplayNumber1(3, '0' + ((Number1 / 1 ) % 10), 0);
}
else if(Number1 < 1000)
{
LCD_DisplayNumber1(0, ' ', 0);
LCD_DisplayNumber1(1, '0' + ((Number1 / 100) % 10), 0);
LCD_DisplayNumber1(2, '0' + ((Number1 / 10 ) % 10), 1);
LCD_DisplayNumber1(3, '0' + ((Number1 / 1 ) % 10), 0);
}
else if(Number1 < 10000)
{
LCD_DisplayNumber1(0, '0' + ((Number1 / 1000) % 10), 0);
LCD_DisplayNumber1(1, '0' + ((Number1 / 100 ) % 10), 0);
LCD_DisplayNumber1(2, '0' + ((Number1 / 10 ) % 10), 1);
LCD_DisplayNumber1(3, '0' + ((Number1 / 1 ) % 10), 0);
}
Number2 = (Number2 + 1) % 10000;
if(Number2 < 10)
{
LCD_DisplayNumber2(0, ' ', 0);
LCD_DisplayNumber2(1, ' ', 0);
LCD_DisplayNumber2(2, '0', 1);
LCD_DisplayNumber2(3, '0' + Number2, 0);
}
else if(Number2 < 100)
{
LCD_DisplayNumber2(0, ' ', 0);
LCD_DisplayNumber2(1, ' ', 0);
LCD_DisplayNumber2(2, '0' + ((Number2 / 10) % 10), 1);
LCD_DisplayNumber2(3, '0' + ((Number2 / 1 ) % 10), 0);
}
else if(Number2 < 1000)
{
LCD_DisplayNumber2(0, ' ', 0);
LCD_DisplayNumber2(1, '0' + ((Number2 / 100) % 10), 0);
LCD_DisplayNumber2(2, '0' + ((Number2 / 10 ) % 10), 1);
LCD_DisplayNumber2(3, '0' + ((Number2 / 1 ) % 10), 0);
}
else if(Number2 < 10000)
{
LCD_DisplayNumber2(0, '0' + ((Number2 / 1000) % 10), 0);
LCD_DisplayNumber2(1, '0' + ((Number2 / 100 ) % 10), 0);
LCD_DisplayNumber2(2, '0' + ((Number2 / 10 ) % 10), 1);
LCD_DisplayNumber2(3, '0' + ((Number2 / 1 ) % 10), 0);
}
MultiTimerStart(&LCD_MultiTimer, 100, LCD_MultiTimerCallback, "LCD");
}
实现效果:
不一样的LCD显示实现方式
软件工程:
|