正点原子IM6基于SDK2.2 > LCD驱动带ASCII打印
#include "fsl_iomuxc.h"
#include "fsl_elcdif.h"
#include "fsl_gpio.h"
#include "td_ledkeybeep.h"
#include "td_lcd_ui_manager.h"
/**********************************************************************************
lcd的多个缓存区
**********************************************************************************/
typedef struct{
unsigned int Buffer[384000];
unsigned char FrameOver;//表示当前帧输出完成
} UIOutBuffer,pUIOutBuffer;
static UIOutBuffer gUIOutBuffer;//双显示器输出缓存区,
//中断回调函数
static void TD_LcdUIManager_IRQ(uint32_t giccIar, void *param);
//给指定的点赋予带透明的颜色
static void TD_LcdUIManager_SetPoint(int x, int y, uint32_t color);
//设置指定点的位图合并颜色,带透明度
static void TD_LcdUIManager_SetColorWithAlpha(uint32_t * pcolor, uint32_t ncolor);
//8*16点阵ascii码位图
extern const unsigned char ASCIICode[96][16];
/**********************************************************************************
正点原子imx6ull中的lcd7寸液晶屏驱动及简单的ui实现
**********************************************************************************/
void TD_LcdUIManager_Init(void)
{
/* 2、配置LCD IO属性
*bit 16:0 HYS关闭
*bit [15:14]: 0 默认22K上拉
*bit [13]: 0 pull功能
*bit [12]: 0 pull/keeper使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 111 驱动能力为R0/7
*bit [0]: 1 高转换率
*/
IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA03_LCDIF_DATA03,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA04_LCDIF_DATA04,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA05_LCDIF_DATA05,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA06_LCDIF_DATA06,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_LCDIF_DATA07,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA08_LCDIF_DATA08,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA09_LCDIF_DATA09,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA10_LCDIF_DATA10,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA11_LCDIF_DATA11,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA12_LCDIF_DATA12,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA13_LCDIF_DATA13,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA14_LCDIF_DATA14,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_LCDIF_DATA15,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA16_LCDIF_DATA16,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA17_LCDIF_DATA17,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA18_LCDIF_DATA18,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA19_LCDIF_DATA19,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA20_LCDIF_DATA20,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA21_LCDIF_DATA21,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA22_LCDIF_DATA22,0);
IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23,0);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA03_LCDIF_DATA03,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA04_LCDIF_DATA04,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA05_LCDIF_DATA05,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA06_LCDIF_DATA06,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_LCDIF_DATA07,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA08_LCDIF_DATA08,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA09_LCDIF_DATA09,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA10_LCDIF_DATA10,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA11_LCDIF_DATA11,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA12_LCDIF_DATA12,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA13_LCDIF_DATA13,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA14_LCDIF_DATA14,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_LCDIF_DATA15,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA16_LCDIF_DATA16,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA17_LCDIF_DATA17,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA18_LCDIF_DATA18,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA19_LCDIF_DATA19,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA20_LCDIF_DATA20,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA21_LCDIF_DATA21,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA22_LCDIF_DATA22,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23,0xB9);
IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK,0);
IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE,0);
IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC,0);
IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC,0);
IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC,0xB9);
IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC,0xB9);
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08,0); /* 背光BL引脚 */
//IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08,0xB9); /* 背光BL引脚 */
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08,
IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |//设置快速翻转io
//IOMUXC_SW_PAD_CTL_PAD_ODE_MASK |//设置开漏输出
//IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |//设置为keeper,1=pull,0=keeper
//IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |//设置开启施密特触发器,可以过滤波形
IOMUXC_SW_PAD_CTL_PAD_DSE(7U) |//输出驱动能力设置为R0/6,0=关闭,1=R0_260_Ohm___3_3V__150_Ohm_1_8V__240_Ohm_for_DDR
IOMUXC_SW_PAD_CTL_PAD_SPEED(2U));// |//速度设置为100mhz,0=50mhz,3=200mhz
//IOMUXC_SW_PAD_CTL_PAD_PKE_MASK |//pull或者keeper功能使能,两个功能互斥
//IOMUXC_SW_PAD_CTL_PAD_PUS(2U));//上下拉设置,2=100k上拉,0=100k下拉
gpio_pin_config_t gp;
/* GPIO初始化 */
gp.interruptMode = kGPIO_IntHighLevel;
gp.direction = kGPIO_DigitalOutput; /* 输出 */
gp.outputLogic = 1; /* 默认关闭背光 */
GPIO_PinInit(GPIO1, 8, &gp); /* 背光默认打开 */
TD_LcdUIManager_BackLedSetTo(1);
/*
* 先初始化video pll
* VIDEO PLL = OSC24M * (loopDivider + (denominator / numerator)) / postDivider
*不使用小数分频器,因此denominator和numerator设置为0
* Initialize the Video PLL.
* Video PLL output clock is OSC24M * (loopDivider + (denominator / numerator)) / postDivider = 93MHz.
*/
clock_video_pll_config_t config = {
.loopDivider = 31, .postDivider = 8, .numerator = 0, .denominator = 0,
};
CLOCK_InitVideoPll(&config);
LCDIF->CTRL = (uint32_t)1<<31; /* 强制复位 */
TD_LcdUIManager_FullRect(0,0,800,480,0xdddddd);
TD_LcdUIManager_FullRect(0,0,800,480,0xdddddd);
LCDIF->CTRL = 0<<31; /* 取消强制复位 */
elcdif_rgb_mode_config_t lcdcfg = {
.panelWidth = 800,
.panelHeight = 480,
.hsw = 48,
.hfp = 40,
.hbp = 88,
.vsw = 3,
.vfp = 13,
.vbp = 32,
.polarityFlags = kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DataEnableActiveHigh | kELCDIF_DriveDataOnRisingClkEdge,
.bufferAddr = (uint32_t)gUIOutBuffer.Buffer,
.pixelFormat = kELCDIF_PixelFormatRGB888,
.dataBus = kELCDIF_DataBus24Bit,
};
ELCDIF_RgbModeInit(LCDIF, &lcdcfg);
ELCDIF_SetNextBufferAddr(LCDIF,(uint32_t)gUIOutBuffer.Buffer);//设置现存的位置
ELCDIF_EnableInterrupts(LCDIF,kELCDIF_CurFrameDoneInterruptEnable);//设置帧结束中断
EnableIRQ(LCDIF_IRQn);//使能总中断
SystemInstallIrqHandler(LCDIF_IRQn,TD_LcdUIManager_IRQ,NULL);
gUIOutBuffer.FrameOver = false;
ELCDIF_RgbModeStart(LCDIF);//启动模块
}
/**********************************************************************************
lcd中断控制,切换双缓冲
**********************************************************************************/
void TD_LcdUIManager_IRQ(uint32_t giccIar, void *param)
{
uint32_t statue = ELCDIF_GetInterruptStatus(LCDIF);//获取中断标志
ELCDIF_ClearInterruptStatus(LCDIF,statue);//清除帧结束中断
gUIOutBuffer.FrameOver = true;
}
/**********************************************************************************
lcd背光控制
**********************************************************************************/
void TD_LcdUIManager_BackLedSetTo(char statue)
{//8位
if(statue) GPIO1->DR |= 0x00000001U << 8;
else GPIO1->DR &= ~(0x00000001U << 8);
}
/**********************************************************************************
lcd显示器多个缓存固定输出底层实现
**********************************************************************************/
void TD_LcdUIManager_Server(void)
{
if(!gUIOutBuffer.FrameOver) return;
//设置显示缓存区
ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)gUIOutBuffer.Buffer);
gUIOutBuffer.FrameOver = false;
}
/**********************************************************************************
将两个颜色的根据透明度合并
**********************************************************************************/
void TD_LcdUIManager_SetColorWithAlpha(uint32_t * pcolor, uint32_t ncolor)
{//00是白色,ff是深色
float opt = (float)(ncolor >> 24) / 0xff;//透明度0-1
int r = (int)(((pcolor[0] >> 16) & 0xff) * (1.0 - opt) + ((ncolor >> 16) & 0xff) * opt + 0.49);
int g = (int)(((pcolor[0] >> 8) & 0xff) * (1.0 - opt) + ((ncolor >> 8) & 0xff) * opt + 0.49);
int b = (int)((pcolor[0] & 0xff) * (1.0 - opt) + (ncolor & 0xff) * opt + 0.49);
pcolor[0] = r << 16 | g << 8 | b;//合成最终颜色
}
/**********************************************************************************
lcd显示器显示指定的图片
**********************************************************************************/
void TD_LcdUIManager_DrawBitmap(uint32_t * buffer, int offect, int len)
{
for(int i = 0;i < len && offect + i < 384000;i++){
gUIOutBuffer.Buffer[offect + i] = buffer[i];
}
ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)gUIOutBuffer.Buffer);
gUIOutBuffer.FrameOver = false;
}
/**********************************************************************************
lcd显示器指定区域将带透明度的数据显示上去
**********************************************************************************/
void TD_LcdUIManager_DrawBitmapWithAlpha(uint32_t * buffer, int offect, int len)
{
for(int i = 0;i < len && offect + i < 384000;i++){
TD_LcdUIManager_SetColorWithAlpha(&gUIOutBuffer.Buffer[offect + i],buffer[i]);
}
ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)gUIOutBuffer.Buffer);
gUIOutBuffer.FrameOver = false;
}
/**********************************************************************************
lcd显示器显示指定的位置显示基于8*16点阵缩放的ASCII码,支持透明度
**********************************************************************************/
void TD_LcdUIManager_Draw0816Ascii(char ch, int x, int y, uint32_t color)
{
int chid = ch - ' ';
if(chid < 0 || chid > 0x5f) chid = 0x5f;
const unsigned char * pch = ASCIICode[chid];
for(int h = 0;h < 16;h++){
int wmask = pch[h];//0.51为四舍五入
int hst = (y + h) * 800;
for(int w = 0;w < 8;w++){
int wdmk = 0x80 >> w;
TD_LcdUIManager_SetColorWithAlpha(&gUIOutBuffer.Buffer[hst + x + w], (wmask & wdmk) == 0 ? 0 : color);
}
}
// ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)gUIOutBuffer.Buffer);
// gUIOutBuffer.FrameOver = false;
}
/**********************************************************************************
lcd显示器显示指定的区域染成指定的颜色,不支持透明度
**********************************************************************************/
void TD_LcdUIManager_FullRect(int x, int y, int w, int h, uint32_t color)
{
for(int ih = 0;ih < h;ih++){
int hst = (y + ih) * 800;
for(int iw = 0;iw < w;iw++){
gUIOutBuffer.Buffer[hst + x + iw] = color;
}
}
}
/**********************************************************************************
lcd显示器显示指定的区域染成指定的颜色,支持透明度
**********************************************************************************/
void TD_LcdUIManager_DrawRect(int x, int y, int w, int h, uint32_t color)
{
for(int ih = 0;ih < h;ih++){
int hst = (y + ih) * 800;
for(int iw = 0;iw < w;iw++){
TD_LcdUIManager_SetColorWithAlpha(&gUIOutBuffer.Buffer[hst + x + iw], color);
}
}
}
/**********************************************************************************
lcd显示器指定的位置画点,w为宽度参数,0时为一个像素1时为两个5个像素,以此类推
**********************************************************************************/
void TD_LcdUIManager_DrawPoint(int x, int y, uint8_t w, uint32_t color)
{
if(w > 0) TD_LcdUIManager_SetPoint(x, y, color);
for(int i = 0;i < w;i++){
for(int j=0;j < w;j++){
//if(i * i + j * j > w) continue;
TD_LcdUIManager_SetPoint(x + j, y + i, color);
}
}
}
/**********************************************************************************
lcd显示器指定的点染成带透明的颜色
**********************************************************************************/
void TD_LcdUIManager_SetPoint(int x, int y, uint32_t color)
{
int tid = y * 800 + x;
if(tid < 384000 && tid > 0) TD_LcdUIManager_SetColorWithAlpha(&gUIOutBuffer.Buffer[tid], color);
}
/**********************************************************************************
lcd显示器画一条线,w为线的宽度
**********************************************************************************/
void TD_LcdUIManager_DrawLine(int x1, int y1, int x2, int y2, int w, uint32_t color)
{
if((x2 - x1) < (y2 - y1)){//y方向比较长的情况
float k = (float)(x2 - x1) / (y2 - y1);//斜率
for(int y = y1;y < y2 && y > 0 && y < 480;y += y1 > y2 ? -1:1){
int x = (int)(y * k) + x1;//计算对应点
TD_LcdUIManager_DrawPoint(x,y,w,color);
}
}
else {//x方向比较长的情况
float k = (float)(y2 - y1) / (x2 - x1);//斜率
for(int x = x1;x < x2 && x > 0 && x < 800;x += x1 > x2 ? -1:1){
int y = (int)(x * k) + y1;//计算对应点
TD_LcdUIManager_DrawPoint(x,y,w,color);
}
}
}
/*********************************************************************************
在显示屏上输出字符串,支持透明度,fsize为字体大小
**********************************************************************************/
//字体大小定义
#define fsize 8//16
void TD_LcdUIManager_Print(const char* str, uint32_t color)
{
static int x = 0,y = 0;
int index = 0;
char ch;
do{
if(x < 0) {
x = 0;//自动换行
y-=fsize * 2;
}
if(x > (800 - fsize)) {
x = 0;//自动换行
y+=fsize * 2;
}
if(y < 0 || y > (480 - fsize * 2)) {
y = 0;//清屏
TD_LcdUIManager_FullRect(0,0,800,480,0xffffff);
}
ch = *(str + index++);
if(ch > 127)
{
if((unsigned char)*(str + index) < 128) continue;//丢弃不成对的半字节
//uint16_t wch = (ch << 8) | *(str + index++);//汉字等宽字节
TD_LcdUIManager_Draw0816Ascii(0xff, x, y, color);
TD_LcdUIManager_Draw0816Ascii(0xff, x + fsize, y, color);
x += fsize * 2;
continue;
}
switch(ch)
{
case 0: return;//字符串结尾标记
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 28:
case 29:
case 30:
case 31:
continue;
case 7://'\a'//响铃
DV_Beep_SetTime(1);
continue;
case 8://'\b'//退格
x -= fsize;
continue;
case 9://'\t'//横向制表
x += fsize * 4;
continue;
case 10://'\n'//换行
x = 0;
y += fsize * 2;
continue;
case 11://'\v'//纵向制表
continue;//??
case 12://'\f'//换页
x = 0;
y = 480;//清屏
continue;
case 13://'\r'//回车//回到开头
x = 0;
continue;
case 27://'\e'//取消按钮
continue;//???
default:
TD_LcdUIManager_Draw0816Ascii(ch, x, y, color);
x += fsize;
//y += fsize * 2;
break;
}
}while(ch);
}
/**********************************************************************************
自定义函数
**********************************************************************************/
static const char HexChars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', };
void ToolGetHexFromInt(uint32_t val, char* buf)
{
buf[0] = HexChars[(val >> 28) & 0xf];
buf[1] = HexChars[(val >> 24) & 0xf];
buf[2] = HexChars[(val >> 20) & 0xf];
buf[3] = HexChars[(val >> 16) & 0xf];
buf[4] = HexChars[(val >> 12) & 0xf];
buf[5] = HexChars[(val >> 8) & 0xf];
buf[6] = HexChars[(val >> 4) & 0xf];
buf[7] = HexChars[(val >> 0) & 0xf];
buf[8] = 0;
}
void ToolGetHexFromShort(uint16_t val, char* buf)
{
buf[0] = HexChars[(val >> 12) & 0xf];
buf[1] = HexChars[(val >> 8) & 0xf];
buf[2] = HexChars[(val >> 4) & 0xf];
buf[3] = HexChars[(val >> 0) & 0xf];
buf[4] = 0;
}
void ToolGetHexFromByte(uint8_t val, char* buf)
{
buf[0] = HexChars[(val >> 4) & 0xf];
buf[1] = HexChars[(val >> 0) & 0xf];
buf[2] = 0;
}
/**********************************************************************************
单独线程方式运行
**********************************************************************************/
void TD_LcdUIManager_Run(void)
{
TD_LcdUIManager_Init();
while(1) TD_LcdUIManager_Server();
}