正点原子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();
}