打印
[PIC®/AVR®/dsPIC®产品]

PIC18F4520四位总线方式驱动LCD1602

[复制链接]
317|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lvsezhidu|  楼主 | 2025-3-23 15:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
求助:笔者参考PIC16f877四位总线方式驱动LCD1602的显示程序,编写了PIC18F4520四位总线方式驱动LCD1602的C程序,Proteus 8.6仿真不显示,用软件自带的库函数也没调出来,有2个周了,真的快把人逼疯了,不知该怎样调试,能否告知一下调试方法和C代码,,本人只会编译再看仿真,怎么找问题在哪呢,本人用PICC18编译器。

使用特权

评论回复
沙发
lidi911| | 2025-3-23 19:44 | 只看该作者
把你的代码传上来看看吧

使用特权

评论回复
板凳
lvsezhidu|  楼主 | 2025-3-23 22:02 | 只看该作者
//-----------------------------------------------------------------
//  名称: 1602液晶头文件  LCD1602_4BIT.h
//-----------------------------------------------------------------
#ifndef _LCD1602_4BIT_H
   #define _LCD1602_4BIT_H

#include <pic18.h>   //可以省略

#define INT8U   unsigned char
#define INT16U  unsigned int
//#define _XTAL_FREQ 32000000UL
//LCD命令   
#define _LCD_CLEAR        0x01
#define LCD_HOME          0x02
#define LCD_SETMODE       0x04
#define LCD_SETVISIBLE    0x08
#define LCD_SHIFT         0x10
#define LCD_SETFUNCTION   0x20
#define LCD_SETCGADDR     0x40
#define LCD_SETDDADDR     0x80
//=================
//LCD控制引脚
#define  RS    LATBbits.LATB0
#define  RW    LATBbits.LATB1
#define  E     LATBbits.LATB2

//#define  RS    PORTBbits.RB0      //PIC16单片机用法
//#define  RW    PORTBbits.RB1
//#define  E     PORTBbits.RB2
//LCD数据与方向端口定义
#define PORT_LCD_DAT     PORTB       //读引脚用PORTB,不用LATB
#define TRIS_LCD_DAT     TRISB

  #define LATB_LCD_CTL     LATB       //控制口
//#define TRIS_LCD_CTL     TRISB       //控制口方向寄存器

//-----------------------------------------------------------------
// 函数声明
//-----------------------------------------------------------------
void LCD_Initialize(void);
void LCD_BUSY_WAIT(void);
void ClearScreen(void);
void Write_LCD_Command (INT8U data);
void Write_LCD_Data(INT8U data);
void Set_LCD_POS(INT8U r, INT8U c);
void LCD_ShowString(INT8U r, INT8U c,char *str);
void LCD_ShowChar(INT8U r, INT8U c,char ch);

void delay(INT16U xms);         //? ms   MHZ



#endif
//#endif  //多一个也没关系
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
  //-----------------------------------------------------------------
//  名称: 1602液晶C文件  LCD1602_4BIT.c
//-----------------------------------------------------------------
//-----------------------------------------------------------------
//  名称: 工作于四位模式的1602LCD显示程序  参考pic16f877程序
//-----------------------------------------------------------------

#define  _XTAL_FREQ  32000000UL           //32MHZ晶振
#include <pic18.h>

#define INT8U   unsigned char
#define INT16U  unsigned int
#include "LCD1602_4BIT.h"
  
void delay(INT16U xms)         ////延时283us@32MHZ
{
   INT16U a,b;
   for(a=xms;a>0;a--)
     for(b=320;b>0;b--);
}

//-----------------------------------------------------------------
// 液晶初始化
//-----------------------------------------------------------------
void LCD_Initialize(void)
{
    Write_LCD_Command(LCD_SETFUNCTION + 0x08);   //0x28,4位模式,双行,5x7点阵
    delay(15);
    Write_LCD_Command(LCD_SETFUNCTION + 0x08);   //4位模式,双行,5x7点阵
   delay(15);
    Write_LCD_Command(LCD_SETFUNCTION + 0x08);   //4位模式,双行,5x7点阵
    delay(15);
        //以上3句属软件启动,后两句后加的,避免下载后不显示,须关闭电源重开机才显示正常
    Write_LCD_Command(LCD_SETVISIBLE + 0x04); //0x0c,开显示光标,不闪烁
    delay(15);
    //Write_LCD_Command(LCD_SETMODE + 0x02);    //模式设置0x06,自动递增   
    delay(15);
        Write_LCD_Command(0x01);                          //清屏
    delay(15);
        Write_LCD_Command(0x0f);delay(15);       //开显示,显示光标,光标闪烁
        //Write_LCD_Command(0x06);delay(15);       //光标右移
        Write_LCD_Command(0x80);delay(15);       //首行显示位置  
}

//-----------------------------------------------------------------
// 清除屏幕
//-----------------------------------------------------------------
void ClearScreen(void)
{
     Write_LCD_Command(_LCD_CLEAR);              //清屏
     Write_LCD_Command(LCD_SETDDADDR + 0x00);    //光标归位
}

//-----------------------------------------------------------------
// 写LCD命令
//-----------------------------------------------------------------
void Write_LCD_Command(unsigned char cmd)
{

  TRIS_LCD_DAT = 0x00;                  //输出口
  //delay(5)接近1500us @32MHZ 共2个delay(5)改为__delay_ms(2)偏慢,调用库函数慢
  //PORT_LCD_DAT = (cmd & 0xf0) | 0x04;delay(5);  //仿真延时取消也可以
   //PORT_LCD_DAT &= 0xfb; // E = 0;  //取高4位数据  成功
  LATB = cmd & 0xf0;
  RS = 0; RW = 0;E = 1;delay(5);E = 0;

  //PORT_LCD_DAT = (cmd << 4) | 0x04;delay(5);    //仿真延时取消也可以
  LATB = cmd << 4;
   //PORT_LCD_DAT &= 0xfb;  //  E = 0;              //取低4位数据
  RS = 0; RW = 0; E = 1;delay(5);E = 0;
  LCD_BUSY_WAIT();
}

//-----------------------------------------------------------------
// 写LCD数据
//-----------------------------------------------------------------
void Write_LCD_Data(unsigned char dat)
{

  LCD_BUSY_WAIT();
  TRIS_LCD_DAT = 0x00;                 //输出口
  //delay(5)接近1500us @32MHZ 共2个delay(5)改为__delay_ms(2)偏慢,调用库函数慢
  //PORT_LCD_DAT = (dat & 0xf0) | 0x05;    delay(5); //仿真延时取消也可以
  //PORT_LCD_DAT &= 0xfb; //E = 0;
  LATB = dat & 0xf0;
  RS = 1; RW = 0; E = 1;delay(5);E = 0;   //取高4位数据
  
   //PORT_LCD_DAT = (dat << 4) | 0x05;   delay(5); //仿真延时取消也可以
   //PORT_LCD_DAT &= 0xfb; //E = 0;             //取低4位数据
   LATB = dat << 4;
   RS = 1; RW = 0;E = 1;delay(5);E = 0;

}

//-----------------------------------------------------------------
// LCD忙等待
//-----------------------------------------------------------------

void LCD_BUSY_WAIT(void)
{  
   INT8U Hi,Lo;

   TRIS_LCD_DAT = 0xf0;            //高4位输入,低4位输出
  //delay(5) delay(10)需2分12秒显示,单个字符定位准确,显示字符串完整 32MHZ
  //delay(5)接近1500us @32MHZ 共4个delay(5)改为__delay_ms(2)
//用__delay_ms(2)仿真用4分钟显示字符
    do{  
         //PORT_LCD_DAT = 0x00;      //端口写0
        LATB=0x00;                   //寄存器写0
         RW = 1;RS = 0;
        E = 1;delay(5);Hi = PORT_LCD_DAT;delay(5);E = 0; //这里不能加延时
        E = 1;delay(5);Lo = PORT_LCD_DAT;delay(5);E = 0;
      //PORT_LCD_DAT = 0x06;__delay_ms(2);Hi = PORT_LCD_DAT;__delay_ms(2);E = 0;
      //PORT_LCD_DAT |= 0x04;__delay_ms(2);Lo = PORT_LCD_DAT;__delay_ms(2);E = 0;
     }while(Hi & 0x80);   

}

//-----------------------------------------------------------------
// 设置显示位置(行,列)
//-----------------------------------------------------------------
void Set_LCD_POS(INT8U r, INT8U c)
{
  //
  if(r == 0) Write_LCD_Command(0x80 | c);
  else if(r == 1) Write_LCD_Command(0xc0 | c);
}

//-----------------------------------------------------------------
// 显示字符串(行,列,字符串)
//-----------------------------------------------------------------
void LCD_ShowString(INT8U r, INT8U c,char *str)
{
  INT8U i;
  Set_LCD_POS(r,c);
  //
  for(i = 0; i < 16 && str[i] != '\0';i++)
    { Write_LCD_Data(str[i]); }
  //
  //while(i < 16)
  //  {Write_LCD_Data(' ');i++;    }
}
//-----------------------------------------------------------------
// 显示字符(行,列,字符)
//-----------------------------------------------------------------
void LCD_ShowChar(INT8U r, INT8U c,char ch)
{
  Set_LCD_POS(r,c);
  Write_LCD_Data(ch);
}
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

//PIC18F4520单片机   
// MPLAB IDE V8.60  picc18编译器,支持picc16f的编译器

#include <pic18.h>
//#include <delays.h>
//#include <stdio.h>
//#include <XLCD.h>
//__PROG_CONFIG(1,0xc800);     //
//默认0x0700, 0xc800使能振荡器切换,使能故障保护时钟监视,内部振荡RA6/7作端口引脚  
//__PROG_CONFIG(1,0xc100);      //PIC的配置字1,使能振荡器切换,使能故障保护时钟监视,XT振荡模式
//__PROG_CONFIG(1,0x4800);     //不使能振荡器切换,使能故障保护时钟监视,内部振荡RA6/7作端口引脚
//__PROG_CONFIG(1,0xc200);     //PIC的配置字1 0xc200外部HS振荡
         
__PROG_CONFIG(2,0x0A16);          //PIC的配置字2

__PROG_CONFIG(3,0x8100);      //PIC的配置字3

__PROG_CONFIG(4,0x0081);      //PIC的配置字4
__PROG_CONFIG(5,0xC00F);      //PIC的配置字5

__PROG_CONFIG(6,0xE00F);      //PIC的配置字6

__PROG_CONFIG(7,0x400F);          //PIC的配置字7

#include "LCD1602_4BIT.h"
#define  _XTAL_FREQ  32000000UL           //8MHZ晶振
//32MHZ时钟可以采用最大的延时库函数 __delay_ms(20);

#define INT8U   unsigned char
#define INT16U  unsigned int

//PIC18F4520系统时钟源初始化
void PIC18_OSC_Init(void)
{
   OSCCON = 0x70;          //PIC18F4520的OSCCONbits.IRCF2:0=111内部RC时钟源8MHZ   
   OSCTUNEbits.PLLEN = 1;    //使能内部4倍PLL功能  32MHZ
}
void main(void)
{
    CMCON = 0x07;    // Disable comparators
    ADCON1 = 0x0F;   // Disable Analog functions
    TRISA = 0x00;
    //PIC18_OSC_Init( );            // MHZ
    delay(2000);
    LCD_Initialize();                // Initialize LCD
    delay(2000);
   //检测液晶屏显示情况
    LCD_ShowChar(0,15,'H');     //第0行1列显示字符'H'(行,列,字符)
    //LCD_ShowChar(1,0,'A');     //第0行1列显示字符'A'(行,列,字符)
    delay(2000);delay(20);delay(20);
   LCD_ShowString(0,3,"Testing TC74");     //第0行0列显示(行,列,字符串)
   // LCD_ShowString(1,1,"Thermal sensor");   //第1行0列显示
    //__delay_ms(20);__delay_ms(20);__delay_ms(20);__delay_ms(20);
   delay(1);                     //延时283us@32MHZ
    //Write_LCD_Command(_LCD_CLEAR);       // CLEAR display
   PORTA = 0xff; delay(2000);
   PORTA = 0x00; delay(2000);
   while(1);        
}                

  

pic16f877仿真通过

使用特权

评论回复
地板
lvsezhidu|  楼主 | 2025-3-23 22:16 | 只看该作者
RB4~RB7接液晶屏的D4~D7

使用特权

评论回复
5
xch| | 2025-3-24 09:17 | 只看该作者
是不是液晶屏供电有问题?

使用特权

评论回复
6
lvsezhidu|  楼主 | 2025-3-24 10:40 | 只看该作者
现在是Proteus仿真没通过,下载也没通过

使用特权

评论回复
7
玄德| | 2025-3-24 12:05 | 只看该作者

先编一段程序,测试 RS、RW、E、data 等内容,确保每个管脚的操作都是正确的。
比如:单步运行 RS = 0,用万用表或者示波器实测 RS 信号是不是零;然后 RS = 1,实测输出对不对。

确保每个信号的操作都正确,剩下就是照搬例程了。



使用特权

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

本版积分规则

3

主题

15

帖子

0

粉丝