[PIC®/AVR®/dsPIC®产品] 877A单片机用MPLAB X IDE写一个LCD12864的程序出现异常

[复制链接]
2433|20
 楼主| tree844 发表于 2021-12-6 23:31 | 显示全部楼层 |阅读模式
本帖最后由 pzsh 于 2021-12-24 11:20 编辑

单片机型号是PIC16F877A。
我在写一个LCD12864的程序,问题出在忙检测函数。并行数据的读写通过PORTD口。
一开始我的程序是这样的:
  1. void BusyCheck(void)
  2. {
  3.     unsigned char temp;
  4.     TRISD = 0xFF;       //数据口设为输入
  5.     RS = 0;
  6.     RW = 1;
  7.     while(1)
  8.     {
  9.         E = 1;
  10.         temp = PORTD;   //读取DB7
  11.         E = 0;
  12.         if((temp & 0x80) == 0)
  13.         {
  14.             TRISD = 0x00;
  15.             break;
  16.         }            
  17.     }   
  18. }
但是一直跳不出while循环。
之后我添加了一个__bit类型的变量busy,就能正常运行了,函数改为如下:
  1. void BusyCheck(void)
  2. {
  3.     busy = 1;
  4.     unsigned char temp;
  5.     TRISD = 0xFF;       //数据口设为输入
  6.     RS = 0;
  7.     RW = 1;
  8.     while(busy)
  9.     {
  10.         E = 1;
  11.         temp = PORTD;   //读取DB7
  12.         E = 0;
  13.         if((temp & 0x80) == 0)
  14.         {
  15.             TRISD = 0x00;
  16.             busy = 0;            
  17.         }            
  18.     }   
  19. }
甚至我还做了如下调试:根据第二种程序,别的什么都不该,就是把while语句的判断条件改成while(1),程序就不能正常执行。
  1. void BusyCheck(void)
  2. {
  3.     busy = 1;
  4.     unsigned char temp;
  5.     TRISD = 0xFF;       //数据口设为输入
  6.     RS = 0;
  7.     RW = 1;
  8.     while(1)//仅仅修改此处,把while(busy)改成while(1)
  9.     {
  10.         E = 1;
  11.         temp = PORTD;   //读取DB7
  12.         E = 0;
  13.         if((temp & 0x80) == 0)
  14.         {
  15.             TRISD = 0x00;
  16.             busy = 0;
  17.             break;
  18.         }            
  19.     }   
  20. }


但是从逻辑上讲,如果busy = 0;能被执行,那么break肯定也能;break能执行又怎么会一直死在while语句里面不能出来呢?之后我进行了单步调试,结果更加令我诧异:
采用第一种程序(即不用busy变量),temp读取的值最高位一直是1,通常是0x81;而改用第二种程序,temp就能读取到0x00。但是我除了这个函数之后没有改变任何其他地方,为什么temp从PORTD口读到的值会不同呢?

 楼主| tree844 发表于 2021-12-6 23:34 | 显示全部楼层
完整程序如下:
  1. // CONFIG
  2. #pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
  3. #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
  4. #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
  5. #pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
  6. #pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
  7. #pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
  8. #pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
  9. #pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

  10. #include <xc.h>

  11. #define _XTAL_FREQ 4000000

  12. __bit busy;
  13. #define RS   RA5
  14. #define RW   RA4
  15. #define E    RA3
  16. #define PSB  RA2
  17. #define nRST RA1

  18. void init(void);
  19. void BusyCheck(void);
  20. void WriteCmd(unsigned char cmd);
  21. void WriteData(unsigned char dat);
  22. void SetPos(unsigned char x, unsigned char y);
  23. void Dis_Str(unsigned char *s);
  24. void init_LCD(void);

  25. void main(void)
  26. {
  27.     unsigned char sec = 0;
  28.     init();
  29.    
  30.     init_LCD();
  31.    
  32.     SetPos(0,1);
  33.     Dis_Str("第一行,第二格");
  34.     SetPos(2,2);
  35.     Dis_Str("time:");
  36.     while(1)
  37.     {
  38.         SetPos(2,6);
  39.         __delay_ms(1000);
  40.         sec++;
  41.         if(sec > 60)
  42.             sec = 0;
  43.         WriteData(sec / 10 + '0');
  44.         WriteData(sec % 10 + '0');
  45.     }
  46. }

  47. void init(void)
  48. {
  49.     PORTA = 0x02;
  50.     TRISA = 0x00;
  51.     ADCON1 = 0x06;
  52.    
  53.     PORTD = 0x00;
  54.     TRISD = 0x00;
  55. }

  56. void BusyCheck(void)
  57. {
  58.     busy = 1;
  59.     unsigned char temp;
  60.     TRISD = 0xFF;       //数据口设为输入
  61.     RS = 0;
  62.     RW = 1;
  63.     while(busy)
  64.     {
  65.         E = 1;
  66.         temp = PORTD;   //读取DB7
  67.         E = 0;
  68.         if((temp & 0x80) == 0)
  69.         {
  70.             TRISD = 0x00;
  71.             busy = 0;
  72.             break;                   //照理说这里的brake语句可以跳出循环,但是不行,必须用busy变量的方法,原因不明。
  73.         }            
  74.     }   
  75. }

  76. void WriteCmd(unsigned char cmd)
  77. {
  78.     BusyCheck();
  79.     RS = 0;
  80.     RW = 0;
  81.     E = 1;
  82.     PORTD = cmd;
  83.     E = 0;
  84. }

  85. void WriteData(unsigned char dat)
  86. {
  87.     BusyCheck();
  88.     RS = 1;
  89.     RW = 0;
  90.     E = 1;
  91.     PORTD = dat;
  92.     E = 0;
  93. }

  94. void SetPos(unsigned char x, unsigned char y)
  95. {
  96.     unsigned char pos;
  97.     switch(x)
  98.     {
  99.         case 0:x = 0x80;break;
  100.         case 1:x = 0x90;break;
  101.         case 2:x = 0x88;break;
  102.         case 3:x = 0x98;break;
  103.         default:break;
  104.     }
  105.     pos = x + y;
  106.     WriteCmd(pos);
  107. }

  108. void Dis_Str(unsigned char *s)
  109. {
  110.     while(*s)
  111.         WriteData(*s++);
  112. }

  113. void init_LCD(void)
  114. {
  115.     nRST = 1;   
  116.     PSB = 1;   
  117.     WriteCmd(0x30);
  118.     WriteCmd(0x0C);
  119.     WriteCmd(0x01);
  120.     __delay_ms(1000);
  121. }


 楼主| tree844 发表于 2021-12-7 22:05 | 显示全部楼层
有大神遇到过这种问题吗?
 楼主| tree844 发表于 2021-12-8 21:38 | 显示全部楼层
时序之类的应该没有问题,硬件可能性也不大。
pzsh 发表于 2021-12-9 10:00 | 显示全部楼层
877A比较老了,如果可能的话,用新的料号使用MCC试一下
 楼主| tree844 发表于 2021-12-9 10:02 | 显示全部楼层
pzsh 发表于 2021-12-9 10:00
877A比较老了,如果可能的话,用新的料号使用MCC试一下

确实老了,只作学习之用。
关键在于,我看不出程序中的逻辑问题,我觉得以上三种程序应该都能运行才对啊。
lcczg 发表于 2021-12-9 15:33 | 显示全部楼层
直接读RD7呐?
if(PORTDbits.RD7 == 0)
 楼主| tree844 发表于 2021-12-9 19:26 | 显示全部楼层
lcczg 发表于 2021-12-9 15:33
直接读RD7呐?
if(PORTDbits.RD7 == 0)

根据LCD的datasheet,并不能这样做,必须在 E = 0 之前先用一个变量暂时存储数据。
我的疑惑主要是在:第一、第三种程序在逻辑上是可行的,和第二种程序相比改动也极小,为什么却读取不到LCD的准备完成信号。
tpgf 发表于 2022-1-4 13:18 | 显示全部楼层
这个是一个并口屏?

评论

是的。  发表于 2022-1-11 21:20
renzheshengui 发表于 2022-1-4 13:20 | 显示全部楼层
是不是晶振的问题啊  能初始化成功吗

评论

不是晶振的问题,我的开发板功能是正常的。  发表于 2022-1-11 21:21
wakayi 发表于 2022-1-4 13:21 | 显示全部楼层
io口需要配置成什么模式呢

评论

我在 init() 函数中有配置,您可以看下。  发表于 2022-1-11 21:22
wowu 发表于 2022-1-4 13:22 | 显示全部楼层
会不会是干扰信号产生的呢

评论

应该不是,就是改了代码就好了。  发表于 2022-1-11 21:22
xiaoqizi 发表于 2022-1-4 13:33 | 显示全部楼层
是不是工具的问题啊

评论

硬件连接和开发板是没有问题的,最大的可能是MPLAB X IDE,或者说XC8编译器,这个工具我在用的时候软件方面遇到一些奇怪的问题,我会单独开个帖子讲。  发表于 2022-1-11 21:24
木木guainv 发表于 2022-1-4 13:37 | 显示全部楼层
稍微调整一下延时呢

评论

和延时绝对没有关系。  发表于 2022-1-11 21:24
ar3000a 发表于 2022-2-10 03:11 | 显示全部楼层
根据经验,同样型号的LCD,品牌多质量差距大,出问题的几率大。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:莫等闲、白了少年头,空悲切!

13

主题

243

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部