stoner 发表于 2005-5-13 10:30:06

求助看看我改的neutronlmk中子关于1602液晶的程序,有bug,不知道在哪里?

我把neutronlmk中子关于1602液晶的程序,中间一部分,表达的方式修改了,但是出现了问题。

编译环境:ICCAVR6.31A

修改的地方:

   直接进行位定义和位操作,让程序更加的直观易懂;

出现的bug:

   isp下载编程,在下载成功的前提下,有时候能够显示,有时候不能显示;在偶尔能够显示的情况下,断电后再上电重开,又不显示了。



修改后的程序如下:

#include <iom16v.h>

#include <macros.h>



//数据线:PC0-PC7------>液晶D0-D7

//控制线:PD0-->RS;

//      PD1-->R/W;

//      PD2-->E;



// 定义一个寄存器(Register)或端口(Port)的八个位

typedef struct _bit_struct

{

    unsignedbit0 : 1 ;

    unsignedbit1 : 1 ;

    unsignedbit2 : 1 ;

    unsignedbit3 : 1 ;

    unsignedbit4 : 1 ;

    unsignedbit5 : 1 ;

    unsignedbit7 : 1 ;

    unsignedbit6 : 1 ;

}bit_field;



//定义一个宏,用来得到每一位的值,利用强制类型转换和指针

#define GET1_BITFIELD(PORTC) (*(volatilebit_field *)0x35)



#define GET2_BITFIELD(PORTD) (*(volatilebit_field *)0x32)



#define GET3_BITFIELD(DDRC) (*(volatilebit_field *)0x34)



#define GET4_BITFIELD(PIND) (*(volatilebit_field *)0x30)

//C语言关键字volatile确保本条指令不会因C编译器的优化而被省略.

//(bit_field *)(0x35)强制转换0x35为结构变量bit_field型的指针

//*,相当于引用这个地址上的内容



//定义寄存器或端口的地址(一般已经包含在头文件中了,本步可不做

//#define PORTc0x35



//定义每一个位



#define LCD_busy GET1_BITFIELD(PORTC).bit7

//忙信号

#define LCD_RSGET2_BITFIELD(PORTD).bit0

//数据、命令选择端,1-数据,0-指令

#define LCD_RWGET2_BITFIELD(PORTD).bit1

//读写选择端,1-读,0-写

#define LCD_ENGET2_BITFIELD(PORTD).bit2

//液晶使能

#define LCD_busy_ddrGET3_BITFIELD(DDRC).bit7

#define LCD_busy_pinGET4_BITFIELD(PINC).bit7

//检测忙信号



#define LCD_data_port PORTC

#define LCD_data_ddr DDRC

#define LCD_control_port PORTD

#define LCD_control_ddr DDRD





void delay_1ms(void );

void delay(unsigned int n) ;



void init_LCD_portCD(void);

void init_LCD(void);

void LCD_busy_en(void);

void LCD_write_order(unsigned char order,unsigned char lcd_busy_flag);

void LCD_write_data(unsigned char data);

void display_a_char(unsigned char position,unsigned char char_data);

void display_a_string(unsigned char col,unsigned char *ptr);

unsigned char str1[]="   stoner   ";

unsigned char str2[]="buaamse   ";



void main(void)

{

   init_LCD_portCD();

   init_LCD();

    while(1)

   {

    display_a_string(0,str1);

           display_a_string(1,str2);

    }

}



void init_LCD_portCD(void)

{

    LCD_data_port=0XFF;

    LCD_data_ddr=0XFF;

    LCD_control_port=0X07;

    LCD_control_ddr=0X07;

}



void init_LCD(void)

{

//1-延时15ms

//2-写指令38H(不检测忙信号)

//3-延时5ms

//4-写指令38H(不检测忙信号)

//5-延时5ms

//6-写指令38H(不检测忙信号)

   delay(15);

   LCD_write_order(0x38,0);

   delay(5);

   LCD_write_order(0x38,0);

   delay(5);

   LCD_write_order(0x38,0);

//   delay(5);

//7-(以后每次写指令、读写数据操作之前均需要检测忙信号)

//8-写指令38H:显示模式设置

//9-写指令08H:显示关闭

//10-写指令01H:显示清屏

//11-写指令06H:显示光标移动设置

//11-写指令0cH:显示开及光标设置

   LCD_write_order(0x38,1);

   LCD_write_order(0x08,1);

   LCD_write_order(0x01,1);

   LCD_write_order(0x06,1);

   LCD_write_order(0x0c,1);

}



//正常读写操作之前必须检测LCD控制器状态

//检测忙信号、等待LCD空闲函数:E=1 RS=0 RW=1;DB7: 0 LCD控制器空闲,1 LCD控制器忙。

void LCD_busy_en(void)

{

   LCD_busy_ddr=0;//设置PC口D7-busy口为输入

   LCD_RS=0;

   LCD_RW=1;

   NOP();

   LCD_EN=1;

   while(LCD_busy_pin&LCD_busy);//等待D7-busy=0,表示准备好,若LCD_busy=1,则一直死循环等待变为0

   LCD_EN=0;

   LCD_busy_ddr=1;   

}



//写指令函数: E=高脉冲 RS=0 RW=0 D0-D7=指令码

//order为指令,指定是否要检测LCD忙信号

void LCD_write_order(unsigned char order,unsigned char lcd_busy_flag)

{

   if(lcd_busy_flag==1)LCD_busy_en();//若lcd_busy_flag为1,则要检测LCD忙信号,等待其空闲

   LCD_RS=0;

   LCD_RW=0;

   LCD_EN=0;//高脉冲

   NOP();

   LCD_EN=1;

   LCD_data_port=order;

   LCD_EN=0;

}



//写数据函数: E =高脉冲 RS=1 RW=0

void LCD_write_data(unsigned char data)

{

   LCD_busy_en();

   LCD_RS=1;

   LCD_RW=0;

   LCD_EN=0;//高脉冲

   NOP();

   LCD_EN=1;

   LCD_data_port=data;

   LCD_EN=0;   

}



//显示一个字符函数

//指定位置显示一个字符:第一行位置0~15,第二行16~31

//因为LCD第一行显示寄存器地址0X80-0X8F,第二行显示寄存器地址:0XC0-0XCF

//参数position指定位置0~31,char_data为要显示的字符

void display_a_char(unsigned char position,unsigned char char_data)

{

        unsigned char position_tem;

        if(position>=0x10)

        position_tem=position+0xb0;

        else

        position_tem=position+0x80;

        LCD_write_order(position_tem,1);

        LCD_write_data(char_data);

}

//指定一行显示连续字符串:0显示在第一行,1显示在第二行,注字符串不能长于16个字符

//显示一行连续字符串函数

void display_a_string(unsigned char col,unsigned char *ptr)//参数col指定行,*ptr指字符串数组的首指针

{

        unsigned char col_tem,i;

        col_tem=col<<4;//若col为1(即在LCD第二行显示字符串),先把col左移4位,使显示字符的首位置改到第二行首位,即位置16

        for(i=0;i<16;i++)

        display_a_char(col_tem++,*(ptr+i));

}



/*************延时程序*******************/

void delay_1ms(void )//延时1ms

{

        unsigned int i ;

   for (i=0;i<600;i++);

}



void delay(unsigned int n)//延时nms

{

        unsigned int i=0 ;

        for(i=0;i<n;i++)

        {

       delay_1ms();

        }

}





neutronlmk中子的源程序如下:

点击此处下载armok0148962.zip

machao 发表于 2005-5-13 14:09:37

先配置芯片的熔丝位,允许BOD监测,检测电压设置为4.0v试试。

stoner 发表于 2005-5-22 16:20:29



先配置芯片的熔丝位,允许BOD监测,检测电压设置为4.0v试试”



马老师,试过之后还是不行,问题还在寻找过程中....痛苦ing..........

pickapple 发表于 2005-7-17 21:02:59

你可以参考一下阿莫的范例

应该是初始化的问题

在范例里只要将初始化函数的0x28改成0x20循环3次就可以了

jarkarta 发表于 2005-7-20 12:24:37

我原来也是怀疑,网站的范例有问题,看来也有人碰到了。

楼上的解决方法是对的。

HJJourAVR 发表于 2005-7-28 11:20:33

不知道这样定义了位域有多大好处?

51扩展位操作,AVR不一定要。



#define LCD_RSGET2_BITFIELD(PORTD).bit0

#define LCD_RWGET2_BITFIELD(PORTD).bit1



LCD_RS=1;

LCD_RW=1;



未必就好用过下面的写法

#define LCD_RS0

#define LCD_RW1



PORTD|=(1<<LCD_RS);

PORTD|=(1<<LCD_RW);



PORTD|=(1<<LCD_RS)|(1<<LCD_RW);这样有优化能力



或写成宏指令

#define LCD_RS_0PORTD&=~(1<<0)

#define LCD_RS_1PORTD|= (1<<0)

#define LCD_RW_0PORTD&=~(1<<1)

#define LCD_RW_1PORTD|= (1<<1)

hao3361 发表于 2007-7-11 01:34:56

谢谢,三楼,我去试试,范例是有些问题的,刚下载可以,重新上电就乱码了

lidewangatan 发表于 2009-3-27 11:33:23

LCD_EN=0;//高脉冲
   NOP();
   LCD_EN=1;
   LCD_data_port=data;
   LCD_EN=0;   
时序有问题
页: [1]
查看完整版本: 求助看看我改的neutronlmk中子关于1602液晶的程序,有bug,不知道在哪里?