[Shanghai Hangxin ACM32F070 development board + touch function evaluation board] 03. Different LCD display implementation methods
[Copy link]
The ACM32F070 series MCU has a segment LCD display controller that supports up to 8 common terminals (COM) and 40 segment terminals (SEG), and can drive 160 (4*40) or 288 (8*36) LCD segments. The main features are as follows:
Highly flexible frame rate control
Supports static, 1/2, 1/3, 1/4, 1/6 and 1/8 duty cycles
Supports 1/2, 1/3, 1/4 bias
Up to 16 registers of LCD data RAM
LCD contrast can be configured by software
Supports Class A and Class B waveforms
2 driving waveform generation methods
- Internal resistor voltage division, external resistor voltage division
- Optional filter capacitor
- The power consumption of the internal resistor voltage division method can be configured by software to match the capacitor charge required by the LCD panel
Support low power mode: LCD controller can display in Active, Sleep, Stop mode
Configurable frame interrupt
Support LCD flashing function and configurable multiple flashing frequencies
Unused LCD segments and common pins can be configured as digital or analog functions
The official program provides a sample program for LCD_TK. The LCD implementation supports three types of LCD screens. The LCD model we got is YR1618A. For the underlying display driver of the LCD screen, the official sample program defines many macros, and then encapsulates functions to implement functions through these macro definitions. After reading the official sample program for a long time, I can understand his programming ideas. The specific macro definitions need to be modified one by one according to the connection method between the LCD truth table and the MCU. If you switch to another screen, the modification content and workload are a bit hesitant. So here I introduce and recommend a set of LCD implementation methods that I often use: realizing the LCD display function through table lookup and mapping.
This method makes the program more readable, easy to transplant, highly compatible, and the functions implemented can be flexibly adjusted according to display needs... Specifically, we need to prepare the following parts:
1. For the contents of the 8-segment combination display, we have enumerated all the characters that can be displayed. We can obtain the display status of the A~G segments corresponding to these display characters by looking up the table;
2. Compare the LCD truth table and map the hardware connection relationship between the LCD pins and the MCU pins into a table. Through this table, we can easily find the COM and SEG subscripts corresponding to the segments to be displayed.
3. Use the COM and SEG subscripts to operate the display buffer register of the LCD in the MCU, and display the content on the screen.
The specific code implementation is as follows:
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");
}
Effect:
不一样的LCD显示实现方式
Software Engineering:
|