微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 12864驱动异常

12864驱动异常

时间:10-02 整理:3721RD 点击:
初始化后出现线条乱码,可以正常显示,不过显示空间被压缩到中下部很小的一部分空间了。



感觉很奇怪。之前用5V,STC单片机驱动没有问题的,现在换3.3V,STM32就出现问题了。估计是初始化时序,还在测试调试中!

#define _LCD_DRV_C_
#include "Drv.h"
#include "Fmm.h"

//----------------------------------------------------------
void Delay(INT16U times)
  {
   while(times)
   {
    times--;
   }
  }
//----------------------------------------------------------
void M_Delay(INT16U NOs)
  {
   while(NOs)
   {
    Delay(200);
    NOs--;
   }
  }

//----------------------------------------------------------
//IO输入
void IOInitIn()
{
    GPIO_InitTypeDef InitType;
    InitType.GPIO_Speed=GPIO_Speed_50MHz;
    InitType.GPIO_Pin = DATAH;
    InitType.GPIO_Mode=GPIO_Mode_IN_FLOATING;//数据引脚为浮空输入
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_Init(GPIOB,&InitType);
   
    InitType.GPIO_Speed=GPIO_Speed_50MHz;
    InitType.GPIO_Pin = DATAL0;
    InitType.GPIO_Mode=GPIO_Mode_IN_FLOATING;//数据引脚为浮空输入
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    GPIO_Init(GPIO_LCD_CMD_DATAL0_SELECT,&InitType);
        
    InitType.GPIO_Speed=GPIO_Speed_50MHz;
    InitType.GPIO_Pin = DATAL1;
    InitType.GPIO_Mode=GPIO_Mode_IN_FLOATING;//数据引脚为浮空输入
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
    GPIO_Init(GPIO_LCD_CMD_DATAL1_SELECT,&InitType);
  
}
//IO输出
void IOInitOut()
{
  GPIO_InitTypeDef InitType;
    InitType.GPIO_Speed=GPIO_Speed_50MHz;
    InitType.GPIO_Pin = DATAH;
    InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_Init(GPIOB,&InitType);
   
    InitType.GPIO_Speed=GPIO_Speed_50MHz;
    InitType.GPIO_Pin = DATAL0;
    InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    GPIO_Init(GPIO_LCD_CMD_DATAL0_SELECT,&InitType);
        
    InitType.GPIO_Speed=GPIO_Speed_50MHz;
    InitType.GPIO_Pin = DATAL1;
    InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
    GPIO_Init(GPIO_LCD_CMD_DATAL1_SELECT,&InitType);
   
   
     InitType.GPIO_Speed=GPIO_Speed_50MHz;//RS
     InitType.GPIO_Pin = PORT_LCD_RS;
     InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
     GPIO_Init(GPIO_LCD_RS,&InitType);
     
     
     InitType.GPIO_Speed=GPIO_Speed_50MHz;//RW
     InitType.GPIO_Pin = PORT_LCD_RW;
     InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
     GPIO_Init(GPIO_LCD_RW,&InitType);
     
     InitType.GPIO_Speed=GPIO_Speed_50MHz;//EN
     InitType.GPIO_Pin = PORT_LCD_EN;
     InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
     GPIO_Init(GPIO_LCD_EN,&InitType);
     
     
      InitType.GPIO_Speed=GPIO_Speed_50MHz;//CS1
     InitType.GPIO_Pin = PORT_LCD_CS1;
     InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
     GPIO_Init(GPIO_LCD_CS1,&InitType);
     
      InitType.GPIO_Speed=GPIO_Speed_50MHz;//CS2
     InitType.GPIO_Pin = PORT_LCD_CS2;
     InitType.GPIO_Mode=GPIO_Mode_Out_PP;//数据引脚为推挽输出
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
     GPIO_Init(GPIO_LCD_CS2,&InitType);
     
     
     
  
}
//检测忙
void CheckState()       
{

  GPIO_WriteBit(GPIO_LCD_RS,
                PORT_LCD_RS,
                (BitAction)PIN_LCD_RS_ENABLE);
   GPIO_WriteBit(GPIO_LCD_RW,
                PORT_LCD_RW,
                (BitAction)PIN_LCD_RW_DISABLE);

    GPIO_WriteBit(GPIO_LCD_EN,
                PORT_LCD_EN,
                (BitAction)PIN_LCD_EN_DISABLE);        //EN下降沿
     IOInitIn();
     while(GPIO_ReadInputData(GPIOB) & 0x0100);
     GPIO_WriteBit(GPIO_LCD_EN,
                PORT_LCD_EN,
                (BitAction)PIN_LCD_EN_ENABLE);        //EN下降沿
IOInitOut();
  
}
/*写命令到LCD*/
void SendCommandToLCD(INT8U com)
{
  INT16U Tcom;
  Tcom=com;
  CheckState();//状态检测LCD是否忙
  GPIO_WriteBit(GPIO_LCD_RS,
                PORT_LCD_RS,
                (BitAction)PIN_LCD_RS_ENABLE);         //向LCD发送命令。RS=0写指令,RS=1写数据
  GPIO_WriteBit(GPIO_LCD_RW,
                PORT_LCD_RW,
                (BitAction)PIN_LCD_RW_ENABLE);//R/W="L",E="H->L"数据被写到IR或DR
//DATA=com;         //com :命令
GPIOB->ODR=(GPIOB->ODR & 0xfc0f)|((Tcom<<2)&0xfff3);
if(com&0x01)
{
   GPIO_WriteBit(GPIO_LCD_CMD_DATAL0_SELECT,
                DATAL0,
                (BitAction)PIN_LCD_RW_DISABLE);
}
else
{
   GPIO_WriteBit(GPIO_LCD_CMD_DATAL0_SELECT,
                DATAL0,
                (BitAction)PIN_LCD_RW_ENABLE);
}
if(com&0x02)
{
    GPIO_WriteBit(GPIO_LCD_CMD_DATAL1_SELECT,
                DATAL1,
                (BitAction)PIN_LCD_RW_DISABLE);
}
else
{
    GPIO_WriteBit(GPIO_LCD_CMD_DATAL1_SELECT,
                DATAL1,
                (BitAction)PIN_LCD_RW_ENABLE);
}
GPIO_WriteBit(GPIO_LCD_EN,
                PORT_LCD_EN,
                (BitAction)PIN_LCD_EN_DISABLE);//EN下降沿
GPIO_WriteBit(GPIO_LCD_EN,
                PORT_LCD_EN,
                (BitAction)PIN_LCD_EN_ENABLE);//EN下降沿
}
/*设置页0Xb8是页的首地址*/
void SetLine(INT8U page)       
{page=0xb8|page; //1011 1xxx 0<=page<=7设定页地址 --X 0-7,8行为一页64/8=8,共8页
SendCommandToLCD(page);
}
/*设定显示开始行,0xc0是行首地址*/
void SetStartLine(INT8U startline)           
{startline=0xc0|startline; //1100 0000
SendCommandToLCD(startline); //设置从哪行开始:0--63,一般从0行开始显示
}
/*设定列地址--Y 0-63,0x40为列首地址*/
void SetColumn(INT8U column)       
{column=column &0x3f; //column最大值为64,输出 0=<column<=63
column= 0x40|column; //01xx xxxx
SendCommandToLCD(column);
}
/*开关显示,0x3f是开显示,0x3e是关显示*/
void SetOnOff(INT8U onoff)          
{onoff=0x3e|onoff; //0011 111x,onoff只能为0/1
SendCommandToLCD(onoff);
}
/*写显示数据*/
void WriteByte(INT8U dat)       
{
  INT16U Tcom;
  Tcom=dat;
CheckState();//状态检查,LCD是否忙
GPIO_WriteBit(GPIO_LCD_RS,
                PORT_LCD_RS,
                (BitAction)PIN_LCD_RS_DISABLE);         //向LCD发送命令。RS=0写指令,RS=1写数据 //RS=0写指令 RS=1写数据
GPIO_WriteBit(GPIO_LCD_RW,
                PORT_LCD_RW,
                (BitAction)PIN_LCD_RW_ENABLE);//R/W="L",E="H->L"数据被写到IR或DR////R/W="L",E="H->L"数据被写到IR/DR
GPIOB->ODR=(GPIOB->ODR & 0xfc0f)|((Tcom<<2)&0xfff3);
if(dat&0x01)
{
   GPIO_WriteBit(GPIO_LCD_CMD_DATAL0_SELECT,
                DATAL0,
                (BitAction)PIN_LCD_RW_DISABLE);
}
else
{
   GPIO_WriteBit(GPIO_LCD_CMD_DATAL0_SELECT,
                DATAL0,
                (BitAction)PIN_LCD_RW_ENABLE);
}
if(dat&0x02)
{
    GPIO_WriteBit(GPIO_LCD_CMD_DATAL1_SELECT,
                DATAL1,
                (BitAction)PIN_LCD_RW_DISABLE);
}
else
{
    GPIO_WriteBit(GPIO_LCD_CMD_DATAL1_SELECT,
                DATAL1,
                (BitAction)PIN_LCD_RW_ENABLE);
}//dat:显示数据
GPIO_WriteBit(GPIO_LCD_EN,
                PORT_LCD_EN,
                (BitAction)PIN_LCD_EN_DISABLE);//EN下降沿
GPIO_WriteBit(GPIO_LCD_EN,
                PORT_LCD_EN,
                (BitAction)PIN_LCD_EN_ENABLE);//EN下降沿
}
/*选择屏幕 0全屏,1左屏 2右屏*/
void SelectScreen(INT8U screen)          
{switch(screen)
{
case 0:   GPIO_WriteBit(GPIO_LCD_CS1,
                PORT_LCD_CS1,
                (BitAction)PIN_LCD_CS1_DISABLE);//全屏
            GPIO_WriteBit(GPIO_LCD_CS2,
                PORT_LCD_CS2,
                (BitAction)PIN_LCD_CS2_DISABLE);
  break;
  case 1:  GPIO_WriteBit(GPIO_LCD_CS1,
                PORT_LCD_CS1,
                (BitAction)PIN_LCD_CS1_DISABLE);//左屏
            GPIO_WriteBit(GPIO_LCD_CS2,
                PORT_LCD_CS2,
                (BitAction)PIN_LCD_CS2_ENABLE);
  break;
  case 2: GPIO_WriteBit(GPIO_LCD_CS1,
                PORT_LCD_CS1,
                (BitAction)PIN_LCD_CS1_ENABLE);//右屏
            GPIO_WriteBit(GPIO_LCD_CS2,
                PORT_LCD_CS2,
                (BitAction)PIN_LCD_CS2_DISABLE);
  break;
}
}
//初始化液晶
void LcdDrvInit(void)
{
        //初始化端口
        IOInitOut();
        //复位液晶
        //延时
       
        //初始化变量
        memset(&gLcdDrvData,0,sizeof(LCD_DRV_DATA_STRUCT));
}
//初始化液晶端口
void LcdDrvPortInit(void)
{
        GPIO_InitTypeDef InitType;
        InitType.GPIO_Speed=GPIO_Speed_50MHz;
        //置输出上拉
          InitType.GPIO_Pin = DATAH;
        InitType.GPIO_Mode=GPIO_Mode_IN_FLOATING;
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        GPIO_Init(GPIOB,&InitType);
       
}
//延时
void LcdDrvDelay(INT16U DelayTime)
{
        for(;DelayTime>0;DelayTime--);
}
//加载对比度
void LcdDrvLoadContrastValue(INT8U ContrastValue)
{
        //对比度值越界
#if 0
        if(ContrastValue>=CONTRAST_MAX_VALUE)
                return;
        //发送对比度调节命令
        LcdDrvSendLcdData(SEND_LCD_COMMAND,
                DISPLAY_COMMAND_SET_CONTRAST_MODE);
        //发送对比度调节数据
        LcdDrvSendLcdData(SEND_LCD_COMMAND,
                ContrastValue);
#endif
}
//发送液晶数据
void LcdDrvSendLcdData(LCD_DRV_SEND_CMD_DATA_SELECT_Def SelectType,
        INT8U SendData)
{
#if 0
        INT8U i,DelayNop;
        //选择发送类型
        switch(SelectType)
        {
        //发送指令
        case SEND_LCD_COMMAND:
                GPIO_WriteBit(GPIO_LCD_CMD_DATA_SELECT,
                        PORT_LCD_CMD_DATA_SELECT,
                        (BitAction)PIN_LCD_CMD_SELECT);
                break;
        //发送数据
        case SEND_LCD_DATA:
                GPIO_WriteBit(GPIO_LCD_CMD_DATA_SELECT,
                        PORT_LCD_CMD_DATA_SELECT,
                        (BitAction)PIN_LCD_DATA_SELECT);
                break;
        default:
                return;
        }
        //片选
        GPIO_WriteBit(GPIO_LCD_CHIP_SELECT,
                PORT_LCD_CHIP_SELECT,
                (BitAction)PIN_LCD_CHIP_SELECT_ENABLE);
        //发送
        for(i=0;i<8;i++)
        {
                if((SendData&0x80)==0x80)
                        GPIO_WriteBit(GPIO_LCD_SOUT,
                                PORT_LCD_SOUT,
                                (BitAction)PIN_LCD_SOUT_HIGH);                       
                else
                        GPIO_WriteBit(GPIO_LCD_SOUT,
                                PORT_LCD_SOUT,
                                (BitAction)PIN_LCD_SOUT_LOW);                       
                //延时
                DelayNop=DelayNop;DelayNop=DelayNop;
                DelayNop=DelayNop;DelayNop=DelayNop;
                //产生时钟上升沿
                GPIO_WriteBit(GPIO_LCD_SCLK,
                        PORT_LCD_SCLK,
                        (BitAction)PIN_LCD_SCLK_HIGH);                       
                //延时
                DelayNop=DelayNop;DelayNop=DelayNop;
                DelayNop=DelayNop;DelayNop=DelayNop;
                //恢复时钟信号低电平
                GPIO_WriteBit(GPIO_LCD_SCLK,
                        PORT_LCD_SCLK,
                        (BitAction)PIN_LCD_SCLK_LOW);                       
                SendData<<=1;
        }
        //撤消片选
        GPIO_WriteBit(GPIO_LCD_CHIP_SELECT,
                PORT_LCD_CHIP_SELECT,
                (BitAction)PIN_LCD_CHIP_SELECT_DISABLE);
#endif
}

//显示半角汉字/数字/字母
void Displayen(INT8U ss,INT8U page,INT8U column,INT8U *number)
{INT8U i;//选屏参数,page选页参数,column选列参数,number选第几汉字输出
SelectScreen(ss);
column=column&0x3f;
SetLine(page);        //写上半页
SetColumn(column);
for(i=0;i<8;i++)
{WriteByte(number[i]);}
SetLine(page+1);        //写下半页
SetColumn(column);
for(i=0;i<8;i++)
{WriteByte(number[i+8]);}
}


/*显示全角汉字*/
void Display(INT8U ss,INT8U page,INT8U column,INT8U *number)
{INT8U i;        //选屏参数,page选页参数,column选列参数,number选第几汉字输出
SelectScreen(ss);
column=column&0x3f;
SetLine(page);        //写上半页
SetColumn(column); //控制列
for(i=0;i<16;i++)  //控制16列的数据输出
{WriteByte(number[i]);}//i+32*number汉字的前16个数据输出
SetLine(page+1);                 //写下半页
SetColumn(column);           //控制列
for(i=0;i<16;i++)          //控制16列的数据输出
{WriteByte(number[i+16]);}//i+32*number+16汉字的后16个数据输出
}

//液晶驱动
void LcdDrvLoadLcdData(INT8U lin,
        INT8U column,INT8U *LcdData,
        INT8U Len)
{
        INT8U ss=0;
       
        //×?·?
        if(Len==16)
  {
                column=column*8;
       
          //if(column<8) SelectScreen(0);        //如果列队<8(0,1,2,3,4,5,6,7)则写在第一屏上面
                 if(column<64)
            {
                                ss=1;
                   
            }
                        else  
                        {
                                ss=2;
                                column=column-64;
                        }
                lin=lin<<1;
        Displayen(ss,lin,column,LcdData);
        }       
   if(32==Len)
         {
                 column=column*16;
       
                 if(column<64)
            {
                                ss=1;
            }
                        else  
                        {
                                ss=2;
                                column=column-64;
                        }
                 lin=lin<<1;       
                  Display(ss,lin,column,LcdData);
         }
       
}
/*------------------显示边框-------------------------------*/
void frame()
{
        INT8U i;
        SelectScreen(2);
        for (i = 0;i < 8;i++)
        {
                SetLine( i);                                                         //共8页
                SetColumn( 31);                                                        //最后一页
                WriteByte(0xff);                                                                        //ff表示每页的8行全亮
         //#define Page_Add 0xb8        //起始页地址
//#define Start_Line 0xc0        //起始行地址
               
        }
}
/*清屏screen: 0-全屏,1-左屏,2-右屏*/
void ClearScreen(INT8U screen)          
{INT8U i,j;
SelectScreen(screen);
for(i=0;i<8;i++)         //控制页数0-7,共8页
{SetLine(i);
  SetColumn(0);
  for(j=0;j<64;j++)           //控制列数0-63,共64列
  {WriteByte(0x00);} //写点内容,列地址自动加1
}
}
/*初始化LCD*/
void init_lcd()           
{
        CheckState();
SelectScreen(0);
SetOnOff(0); //关显示
SelectScreen(0);
SetOnOff(1); //开显示
SelectScreen(0);
ClearScreen(0);//清屏
SetStartLine(0); //开始行:0
       
       
       
       
}

代码太长没看,但多半是时序问题,检查一下自己的时钟配置

能详细一点吗,我这边检查了一下时钟配置没有看到明显问题。不知如何下手。

你用STC时的总线频率是多少?现在改成STM32后的总线频率是多少?

STC单片机直接用的12M晶振,选用的是传统51单片机的指令周期,应该是1M
STM32也是选用的12M晶振,RCC_HCLKConfig(RCC_SYSCLK_Div1);                   // HCLK = SYSCLK

      /* 设置低速APB2时钟,这个时钟从AHB时钟分频而来分频系数为1,2,4,8,16 */
     RCC_PCLK2Config(RCC_HCLK_Div1);                  // PCLK2 = HCLK

     /* 设置低速APB1时钟,这个时钟从AHB时钟分频而来分频系数为1,2,4,8,16 */
     RCC_PCLK1Config(RCC_HCLK_Div2);                  // PCLK1 = HCLK/2
各种分频都试过还是不行。

不要靠试,要确保总线时钟一样

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top