打印

STM32驱动12864的奇怪问题

[复制链接]
4443|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
小弟用STM32驱动12864遇到个奇怪的问题,12864由ks0108驱动,将要写的数据写入显示ram中,比如将100写入,读回来正确,但是写入0xFF,再读回来发现不是0xFF,不管是写入100还是0xFF,lcd上都没有任何反应,将复位,忙,显示开关状态都读回来,发现没什么问题。实在找不到问题所在。
因为硬件没有经过调试,所以根本不知道是硬件的问题还是软件的问题,希望搞过的朋友帮忙看看。
硬件图:


代码:
/* Private Includes ----------------------------------------*/
#include "LCD.h"
#include <math.h>
#include <stdio.h>
#include "stm32f10x.h"

/* Private Defines ------------------------------------------*/


/* Private Variables*/
extern const unsigned char Asii0610[];

/* Private Functions ---------------------------------------*/

/*
**************************************************************************************************
*
* Function Name: LCD_WriteData
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 通过数据口给LCD写数据
*
* Param : unsigned char data : 要写的8位数
*
* Return : None
*
* Notes: 为底层函数,供上层函数调用
*
*
*
**************************************************************************************************
*/
void LCD_WriteData(unsigned char  data)
{
// printf("LCD_WriteData--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_ConfigDataDirection(LCD_DATA_OUT);
     
    GPIO_SetBits(GPIOB, DI);
    GPIO_ResetBits(GPIOB, WR);
GPIO_SetBits(GPIOB, E);
    GPIO_Write(GPIOA, data);      
    LCD_DelayUs(800);
    GPIO_ResetBits(GPIOB, E);
    LCD_DelayUs(800);
    GPIO_SetBits(GPIOB, E);
// printf("LCD_WriteData--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_WriteCmd
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 通过数据口给LCD写命令
*
* Param : unsigned char cmd : 要写的8位命令值
*
* Return : None
*
* Notes: 为底层函数,供上层函数调用
*
*
*
**************************************************************************************************
*/
void LCD_WriteCmd(unsigned char cmd)
{
// printf("LCD_WriteCmd--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_ConfigDataDirection(LCD_DATA_OUT);
      
    GPIO_ResetBits(GPIOB, DI);
    GPIO_ResetBits(GPIOB, WR);
GPIO_SetBits(GPIOB, E);
    GPIO_Write(GPIOA, cmd);
   
    LCD_DelayUs(800);
    GPIO_ResetBits(GPIOB, E);
    LCD_DelayUs(800);
    GPIO_SetBits(GPIOB, E);  

// printf("LCD_WriteCmd--------end\n\r");   
}

/*
**************************************************************************************************
*
* Function Name: LCD_ReadData
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 通过数据口从LCD读数据
*
* Param : None
*
* Return : unsigned char : 读返回的数据
*
* Notes: 为底层函数,供上层函数调用
*
*
*
**************************************************************************************************
*/
unsigned char LCD_ReadData(void)
{
    unsigned char data = 0;
printf("LCD_ReadData--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_ConfigDataDirection(LCD_DATA_IN);
    GPIO_SetBits(GPIOB, DI);
    GPIO_SetBits(GPIOB, WR);

    //空读操作
    GPIO_SetBits(GPIOB, E);   
    LCD_DelayUs(800);
    GPIO_ResetBits(GPIOB, E);
LCD_DelayUs(800);
    GPIO_SetBits(GPIOB, E);
data = GPIO_ReadInputData(GPIOA);  
    LCD_DelayUs(800);
    GPIO_ResetBits(GPIOB, E);
    LCD_DelayUs(800);
    GPIO_SetBits(GPIOB, E);   
printf("LCD_ReadData--------end\n\r");
printf("ReadData = %d--------begin\n\r", data);
    return data;     
}  
/*
**************************************************************************************************
*
* Function Name: LCD_Open
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 打开LCD,实际为写入显示开指令
*
* Param : None
*
* Return : None
*
* Notes:
*
*
*
**************************************************************************************************
*/
void LCD_Open(void)
{
printf("LCD_Open--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_WriteCmd(0x3F);
printf("LCD_Open--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_Close
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 关闭LCD显示,实际为写入显示关指令
*
* Param : None
*
* Return : None
*
* Notes:
*
*
*
**************************************************************************************************
*/
void LCD_Close(void)
{
printf("LCD_Close--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_WriteCmd(0x3E);
printf("LCD_Close--------end\n\r");
}

void LCD_Delay(int count)
{
    for(; count > 0; count--);
}

LCD_FlagStatus LCD_GetStatus(LCD_Status LCD_FLAG)
{
    unsigned char data;
    LCD_FlagStatus status = LCD_RESET;
// printf("LCD_GetStatus--------begin\n\r");

    LCD_ConfigDataDirection(LCD_DATA_IN);
    GPIO_SetBits(GPIOB, WR);
    GPIO_ResetBits(GPIOB, DI);
    //空读操作
    GPIO_SetBits(GPIOB, E);
    //需要延时一下
    LCD_DelayUs(800);
    GPIO_ResetBits(GPIOB, E);
   
    GPIO_SetBits(GPIOB, E);
    //需要延时一下
    LCD_DelayUs(800);
    GPIO_ResetBits(GPIOB, E);
    LCD_DelayUs(800);
    GPIO_SetBits(GPIOB, E);
    data = GPIO_ReadInputData(GPIOA);
    if(data & LCD_FLAG)
    {
        status = LCD_SET;
    }
    else
    {
        status = LCD_RESET;
//  printf("GetStatus = %d\n\r", status);
    }  
// printf("LCD_GetStatus--------end\n\r");


    return  status;
}

void LCD_SelectPage(unsigned char page)
{
//    printf("LCD_SelectPage--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
LCD_WriteCmd(0xB8 + page);
// printf("LCD_SelectPage--------end\n\r");
}

void LCD_SelectYAddr(unsigned char yAddr)
{
// printf("LCD_SelectYAddr--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_WriteCmd(0x40 + yAddr);
// printf("LCD_SelectYAddr--------end\n\r");
}


void LCD_SelectStartRow(unsigned char startRow)
{
// printf("LCD_SelectStartRow--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_WriteCmd(0xC0 + startRow);
// printf("LCD_SelectStartRow--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_Clear
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 清除整个LCD。
*
* Param : None
*
* Return : None
*
* Notes:
*
*
*
**************************************************************************************************
*/
void LCD_Clear(void)
{
    char i = 0, j = 0;

printf("LCD_Clear--------begin\n\r");
    GPIO_SetBits(GPIOB, CS1);
    for (i = 0; i < LCD_PAGE_END; i++)
    {
        LCD_SelectPage(i);
        LCD_SelectYAddr(0);
        for (j = 0; j < LCD_Y_ADDR_END; j++)
        {            
            LCD_WriteData(0);//列地址自动增1
        }
   
    }  

GPIO_SetBits(GPIOB, CS2);
    for (i = 0; i < LCD_PAGE_END; i++)
    {
        LCD_SelectPage(i);
        LCD_SelectYAddr(0);
        for (j = 0; j < LCD_Y_ADDR_END; j++)
        {            
            LCD_WriteData(0);//列地址自动增1
        }
   
    }
printf("LCD_Clear--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_DispPoint
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 显示LCD上指定的点。
*
* Param : unsigned char x:显示点的行地址,0到63
*         unsigned char y:显示点的列地址,0到127
*
* Return : None
*
* Notes:
*
*
*
**************************************************************************************************
*/
void  LCD_DrawPoint(unsigned char x, unsigned char y)
{
    unsigned char page = 0;
    unsigned char data = 0;

while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
printf("LCD_DrawPoint--------begin\n\r");
    page = x / 8;
    LCD_SelectPage(page);
    LCD_SelectYAddr(y);
    data = LCD_ReadData();
    data = data | (1 << (x % 8));
// data = 0xFF;
    LCD_WriteData(data);
printf("LCD_DrawPoint--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_ClearPoint
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 清除LCD上指定的点。
*
* Param : unsigned char x:显示点的行地址,0到63
*         unsigned char y:显示点的列地址,0到127
*
* Return : None
*
* Notes:
*
*
*
**************************************************************************************************
*/
void LCD_ClearPoint(unsigned char x, unsigned char y)
{
    unsigned char page = 0;
    unsigned char data = 0;
printf("LCD_ClearPoint--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    page = x / 8;
    LCD_SelectPage(page);
    LCD_SelectYAddr(y);
    data = LCD_ReadData();
    data = data & (~(1 << (x % 8)));
    LCD_WriteData(data);
printf("LCD_ClearPoint--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_Configuration
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 配置LCD的时钟,以及命令IO脚。
*
* Param : None
*
* Return : None
*
* Notes: 因为STM32的GPIO口不是双向口,需要配置为输入或者输出,所以数据口的IO根据需要单独配置
*
*
*
**************************************************************************************************
*/
void LCD_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
printf("LCD_Configuration--------begin\n\r");

    //配置LCD的命令管脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;                                 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    //配置LCD的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA, ENABLE);
printf("LCD_Configuration--------end\n\r");
   
}

/*
**************************************************************************************************
*
* Function Name: LCD_ConfigDataDirection
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 配置数据口的方向。
*
* Param : None
*
* Return : None
*
* Notes: 因为STM32的GPIO口不是双向口,需要配置为输入或者输出,所以数据口的IO根据需要单独配置
*
*
*
**************************************************************************************************
*/
void LCD_ConfigDataDirection(LCD_DataDirection direction)
{
GPIO_InitTypeDef GPIO_InitStructure;
// printf("LCD_ConfigDataDirection--------begin\n\r");
    GPIO_InitStructure.GPIO_Mode = (direction ? GPIO_Mode_Out_PP : GPIO_Mode_IN_FLOATING);
    GPIO_InitStructure.GPIO_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_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
// printf("LCD_ConfigDataDirection--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_DispCharAt
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 在指定起始地址出显示一个字符。
*
* Param : unsigned char x :起始地址行号
*         unsigned char y : 起始地址列号
*         unsigned char character:待显示字符(ascii码,能否显示数字,待检测)
*
* Return : None
*
* Notes: 字模文件存在Asii0610文件中,每个字模占10个字节,暂时不支持中文显示,
*        字模文件是否正确有待检测,可用的字模文件还有chinese.c(显示万年历需要的几个中文)
*        和ascii.c(显示数字)
*
*
**************************************************************************************************
*/
void LCD_DispCharAt(unsigned char x, unsigned char y, unsigned char character)
{
    //获取该字符在字模中的位置,每个字模有10个字节
    unsigned char *pChar = (unsigned char *)Asii0610 + (character - 32) * 10;
    unsigned char page = x / 8;
    unsigned char i ;
// printf("LCD_DispCharAt--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    LCD_SelectPage(page);
    LCD_SelectYAddr(y);
    for (i = 0; i < 10; i++)
    {
        LCD_WriteData(*(pChar + i));
    }   
// printf("LCD_DispCharAt--------end\n\r");
}

/*
**************************************************************************************************
*
* Function Name: LCD_DispStringAt
*
* Author: xiepengcheng          Version: 1.0          Date: 2011-05-28
*
* Description: 在指定起始地址出显示一个字符。
*
* Param : unsigned char x :起始地址行号
*         unsigned char y : 起始地址列号
*         unsigned char *pString:指向待显示字符串
*         unsigned char length : 字符串长度
*
* Return : None
*
* Notes: 字模文件存在Asii0610文件中,每个字模占10个字节,暂时不支持中文显示,
*        字模文件是否正确有待检测,可用的字模文件还有chinese.c(显示万年历需要的几个中文)
*        和ascii.c(显示数字)
*        此函数可能有待改进,可以将length参数去掉,因为字符串以'/0'结束
*
*
**************************************************************************************************
*/
void LCD_DispStringAt(unsigned char x, unsigned char y, unsigned char *pString)
{
printf("LCD_DispStringAt--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    while ( (*pString) != '\0')
    {
        LCD_DispCharAt(x, y, *pString);
    }
printf("LCD_DispStringAt--------end\n\r");
}

void LCD_DrawLine(unsigned char startX, unsigned char startY, unsigned char endX, unsigned char endY)
{
    //采用bresenham算法
    char dX = 0, dY = 0, incX = 0, incY = 0, temp = 0, flag = 0, judge = 0;
    char i = 0;
    dX = endX - startX;
    dY = endY - startY;
printf("LCD_DrawLine--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    if (dX > 0)
    {
        incX = 1;
    }
    else
        incX = -1;
    if (dY > 0)
    {
        incY = 1;
    }
    else
        incY = -1;
    dX = abs(dX);
    dY = abs(dY);
    if (dY > dX)
    {
        temp = dY;
        dY = dX;
        dX = temp;
        //x 和 y翻转
        flag = 1;
    }
    else
        flag = 0;
    judge = 2 * dY - dX;
    for( i = 0; i < dX; i++)
    {
        LCD_DrawPoint(startX, startY);
        if (judge > 0)
        {
            if (flag == 0)
                startY = startY + incY;
            else
                startX = startX + incX;
            judge = judge - 2 * dX;
        }
        if (flag == 0)
        {
            startX = startX + incX;
        }
        else
            startY = startY + incY;
        judge = judge + 2 * dY;
    }
printf("LCD_DrawLine--------end\n\r");
}

void LCD_DispNumAt(unsigned char x, unsigned char y, int data)
{
    unsigned char s[64] = {0};
printf("LCD_DispNumAt--------begin\n\r");
while(LCD_GetStatus(LCD_BUSY_FLAG) != RESET);
    sprintf((char *)s, "%s", (char *)data);
    LCD_DispStringAt(x, y, s);
printf("LCD_DispNumAt--------end\n\r");
}
//void LCD_Init(void)
//{
// LCD_Close();
// LCD_DelayUs(400);
//
//}
void LCD_DelayUs(unsigned long n)
{
unsigned long j;
while(n--)
{
  j=8;
    while(j--);
}
}
void LCD_DelayMs(unsigned long n)
{
while(n--)
    LCD_DelayUs(1100);
}


void LCD_DrawTest(void);
void LCD_Test(void);
/* Private functions ---------------------------------------------------------*/

int main(void)
{
    int i;
    LCD_FlagStatus status;
    unsigned char data = 0;

    SystemInit();
    RCC_Config();
    USART_Config();
    LCD_Configuration();
    GPIO_SetBits(GPIOB, CS1);
    GPIO_ResetBits(GPIOB, CS2);
    LCD_Close();
    LCD_Open();
    GPIO_SetBits(GPIOB, CS2);
    GPIO_ResetBits(GPIOB, CS1);
    LCD_Close();
    LCD_Open();
    LCD_WriteData(10);
   data = LCD_ReadData();
   printf("data = %d \n\r", data);
   status = LCD_GetStatus(LCD_ON_OFF_FLAG);
   printf("ON_OFF_STATUS = %d \n\r", status);
   status = LCD_GetStatus(LCD_RESET_FLAG);
   printf("RESET_STATUS = %d \n\r", status);
   status = LCD_GetStatus(LCD_BUSY_FLAG);
   printf("BUSY_STATUS = %d \n\r", status);
   LCD_Test();

   while(1)
   {
       for(i = 3000000; i > 0; i--);
       printf("in main\n\r");  
   }   
}

void LCD_Test(void)
{
    char i = 0, j = 0;
    unsigned char data = 0;

    printf("LCD_Test--------begin\n\r");
    GPIO_SetBits(GPIOB, CS1);
    GPIO_ResetBits(GPIOB, CS2);
    for (i = 0; i < LCD_PAGE_END; i++)
    {
        LCD_WriteCmd(0xc0);
        LCD_SelectPage(i);
        LCD_SelectYAddr(0);
        for (j = 0; j < LCD_Y_ADDR_END; j++)
        {            
            LCD_WriteData(220);//列地址自动增1
        data = LCD_ReadData();
        printf("read_data = %d \n\r", data);
        }
   
    }  

GPIO_ResetBits(GPIOB, CS1);
GPIO_SetBits(GPIOB, CS2);
    for (i = 0; i < LCD_PAGE_END; i++)
    {
        LCD_SelectPage(i);
        LCD_SelectYAddr(0);
        for (j = 0; j < LCD_Y_ADDR_END; j++)
        {            
            LCD_WriteData(220);//列地址自动增1
   data = LCD_ReadData();
   printf("read_data = %d \n\r", data);
        }
   
    }
printf("LCD_Test--------end\n\r");
}

此外,由于疏忽,没有将数据口上拉,所以在每次读写数据的时候,都重新配置数据口,读时配置为浮动输入,写数据的时候配置为推挽输出。并且LCD的rst脚悬空。
沙发
xiepengchenghn|  楼主 | 2011-6-26 23:23 | 只看该作者
没人搭理下俺吗?

使用特权

评论回复
板凳
aihe| | 2011-6-26 23:58 | 只看该作者
没啥注释,又那么长,只有楼主自己去慢慢找问题了

使用特权

评论回复
地板
yzzly| | 2011-6-27 09:22 | 只看该作者
如果LZ保证时序和程序没有错误的话,一般都是由于速度匹配的原因,LCD速度跟不上STM32的速度,可适当降低STM32写LCD的速度试试。

使用特权

评论回复
5
xiepengchenghn|  楼主 | 2011-6-27 18:25 | 只看该作者
4# yzzly

降低STM32写LCD的速度,你指的是时序中延时时间弄长一点?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

267

帖子

1

粉丝