用CVAVR,使用1602显示AD采样的电压,显示异常。开中断的话,字符一闪一闪。关中断,才能显示正常。
主函数:
/*****************************************************
File name : demo_10_3.c
Chip type : ATmega16L
Program type : Application
Clock frequency : 4.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega16.h>
#include "lcd1602.h"
#include <delay.h>
unsigned int adc_data,adc_v;
// ADC 转换完成中断服务
interrupt [ADC_INT] void adc_isr(void)
{
adc_data=ADCW; //读取ADC置换结果
adc_v=(unsigned long)adc_data*2560/1024; //换算成电压值
}
void main(void)
{
// DDRA=0x00;
// PORTA=0x00;
// T/C0 初始化
TCCR0=0x0B; // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
TCNT0=0x00;
OCR0=0x7C; // OCR0 = 0x7C(124),(124+1)/62.5=2ms
TIMSK=0x02; // 允许T/C0比较中断
// ADC 初始化
ADMUX=0xC7; // 参考电源AVcc、ADC7单端输入
SFIOR&=0x1F;
SFIOR|=0x60; // 选择T/C0比较匹配中断为ADC触发源
ADCSRA=0xAD; // ADC允许、自动触发转换、ADC转换中断允许、ADCclk=125Kz
lcd_init();
// #asm("sei") // 开放全局中断
while (1)
{
lcd_locate(1,1);
lcd_string("FMX");
}
}
1602.c
#include "lcd1602.h"
void lcd_init(void) //显示屏初始化函数
{
//EN_CLR;
//lcd_clear();
//DDRB = 0xFF; //I/O口方向设置
LCD_DATA_DDR|=LCD_DATA|LCD_RS|LCD_EN ; //数据口方向为输出
// #asm("cli")
delay_ms(15); //上电延时,以使供电稳定
// #asm("sei")
lcd_write_com(0x33);
lcd_write_com(0x32);
//lcd_en_write();
//delay_lcd_us(40);
lcd_write_com(0x28); //4bit interface,2line,5*7dots
lcd_write_com(0x08); //关显示,不显光标,光标不闪烁
lcd_write_com(0x04); //写一字符,整屏显示不移动
lcd_write_com(0x0c);
// #asm("cli")
delay_ms(5);
// #asm("sei")
//lcd_clear(); 清屏
lcd_clear();
//开显示,光标、闪烁都关闭
//lcd_write_com(0x05); //写一字符,整屏右移
//lcd_write_com(0x06); //写一字符,整屏显示不移动
//lcd_write_com(0x07); //写一字符,整屏左移
//lcd_write_com(0x0B); 关闭显示(不显示字符,只有背光亮)
//lcd_write_com(0x0D); //开显示,不显示光标,但光标闪烁
//lcd_write_com(0x0E); //开显示,显示光标,但光标不闪烁
//lcd_write_com(0x0F); //开显示,光标、闪烁均显示
}
void lcd_en_write(void) //LCD写时序控制EN端产生一个高电平脉冲,控制LCD写时序
{
EN_SET;
// #asm("cli")
delay_us(5);
// #asm("sei")
EN_CLR;
}
void lcd_clear(void)//清屏函数
{
lcd_write_com(0x01);
//#asm("cli")
delay_ms(5);
//#asm("sei")
}
void lcd_write_com(unsigned char lcd_com)//写指令函数
{
//高四位的写法
//#asm("cli")
delay_us(35);
// #asm("sei")
RS_CLR;
lcd_data_port&=0X0f; //清高四位
lcd_data_port|=(lcd_com&0Xf0); //写高四位
lcd_en_write(); //写入指令数据
// #asm("cli")
delay_us(35);
//#asm("sei")
lcd_com=lcd_com<<4; //低四位移到高四位
lcd_data_port&=0X0f; //清高四位
lcd_data_port|=(lcd_com&0Xf0); //写低四位
lcd_en_write(); //写入指令数据
/*
delay_lcd_us(35);
RS_CLR;
lcd_data_port&=0Xf0; //清高四位
lcd_data_port|=(lcd_com&0X0f); //写高四位
lcd_en_write(); //写入指令数据
delay_lcd_us(35);
lcd_com=lcd_com<<4; //低四位移到高四位
lcd_data_port&=0Xf0; //清高四位
lcd_data_port|=(lcd_com&0X0f); //写低四位
lcd_en_write(); //写入指令数据
*/
}
void lcd_write_data(unsigned char lcd_data)//写数据函数
{
// #asm("cli")
delay_us(35);
//#asm("sei")
RS_SET;
//RW_CLR;
lcd_data_port&=0X0f;//清高四位
lcd_data_port|=(lcd_data&0Xf0);//写高四位
lcd_en_write();//写入数据
// #asm("cli")
delay_us(35);
// #asm("sei")
lcd_data=lcd_data<<4;//低四位移到高四位
lcd_data_port&=0X0f;//清高四位
lcd_data_port|=(lcd_data&0Xf0);//写低四位
lcd_en_write();//写入指数据
}
//----------------- LCD显示定位函数,行、列定位----------------------------
void lcd_locate( char x, char y)
{ char aa;
if (x==1) aa=0x80;
if (x==2) aa=0x80+0x40;
lcd_write_com(aa+y-1);
}
void lcd_string(unsigned char const *DData ) //在1602LCD上显示一一串字符
{ //unsigned char aa;
//aa=0;
//while(DData[aa]!='\0') //取字符串是否结束?
//{ lcd_write_data(DData[aa]); //显示单个字符
//aa++;
//}
while(*DData)
{
lcd_write_data(*DData);
DData++;
}
}
void lcd_1_char(unsigned char data_1_char) //在1602LCD上显示一个1位的整数
{ unsigned char lcd_table[2];
lcd_table[1]=data_1_char%10; //获得个位的数字
lcd_write_data(lcd_table[1]+0x30); //显示个位
}
//-------------------------------------------------------------------------
void lcd_2_char(unsigned char data_2_char) //在1602LCD上显示一个2位的整数
{ unsigned char lcd_table[3];
lcd_table[1]=data_2_char/10; //获得十位的数字
lcd_table[2]=data_2_char%10; //获得个位的数字
lcd_write_data(lcd_table[1]+0x30); //显示十位
lcd_write_data(lcd_table[2]+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_3_char(unsigned int data_3_char) //在1602LCD上显示一个3位的整数
{ unsigned int lcd_table[4];
lcd_table[1]=data_3_char/100; //获得百位的数字
lcd_table[2]=data_3_char%100/10; //获得十位的数字
lcd_table[3]=data_3_char%10; //获得个位的数字
lcd_write_data(lcd_table[1]+0x30); //显示百位
lcd_write_data(lcd_table[2]+0x30); //显示十位
lcd_write_data(lcd_table[3]+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_4_char(unsigned int data_4_char) //在1602LCD上显示一个4位的整数
{ unsigned int lcd_table[5];
lcd_table[1]=data_4_char/1000; //获得千位的数字
lcd_table[2]=data_4_char%1000/100; //获得百位的数字
lcd_table[3]=data_4_char%100/10; //获得十位的数字
lcd_table[4]=data_4_char%10; //获得个位的数字
lcd_write_data(lcd_table[1]+0x30); //显示千位
lcd_write_data(lcd_table[2]+0x30); //显示百位
lcd_write_data(lcd_table[3]+0x30); //显示十位
lcd_write_data(lcd_table[4]+0x30); //显示个位
}
//----------------------------------------------------------------------------------
void lcd_5_char(unsigned int data_5_char) //在1602LCD上显示一个5位的整数 void lcd_5_char(unsigned int data_5_char);
{ unsigned int lcd_table[9];
lcd_table[1]=data_5_char%100000/10000; //获得万位的数字
lcd_table[2]=data_5_char%10000/1000; //获得千位的数字
lcd_table[3]=data_5_char%1000/100; //获得百位的数字
lcd_table[4]=data_5_char%100/10; //获得十位的数字
lcd_table[5]=data_5_char%10; //获得个位的数字
lcd_write_data(lcd_table[1]+0x30); //显示万位
lcd_write_data(lcd_table[2]+0x30); //显示千位
lcd_write_data(lcd_table[3]+0x30); //显示百位
lcd_write_data(lcd_table[4]+0x30); //显示十位
lcd_write_data(lcd_table[5]+0x30); //显示个位
}
//-------------------------------------------------------
void lcd_char(unsigned int data_char)
{ unsigned int n;
if(data_char>9999) n=1;
else if(data_char>999) n=2;
else if(data_char>99) n=3;
else if(data_char>9) n=4;
else n=5;
switch(n)
{
case 1:lcd_5_char(data_char); break;
case 2:lcd_4_char(data_char); break;
case 3:lcd_3_char(data_char); break;
case 4:lcd_2_char(data_char); break;
case 5:lcd_1_char(data_char); break;
default : break;
}
}
void lcd_float(float f_data) //在1602LCD上显示一个小于100、保留3位小数的浮点数
{ unsigned char lcd_table[5];
unsigned long aa;
aa=f_data*1000; //保留3位小数
lcd_table[0]= aa/10000 ; //分别获取各位上的数
lcd_table[1]= aa%10000/1000 ;
lcd_table[2]= aa%1000/100 ;
lcd_table[3]= aa%100/10 ;
lcd_table[4]= aa%10 ;
if (lcd_table[0]==0) lcd_write_data(' '); //如果整数部分的十位数是0则不显示(显示空格)
else lcd_write_data(lcd_table[0]+0x30); //显示整数部分的十位数,加上0x30以便直接得到相应的ASCII码去显示
lcd_write_data(lcd_table[1]+0x30); //显示整数部分的个位数
lcd_write_data('.'); //显示小数点"."
lcd_write_data(lcd_table[2]+0x30); //显示小数部分的十分位
lcd_write_data(lcd_table[3]+0x30); //显示小数部分的百分位
lcd_write_data(lcd_table[4]+0x30); //显示小数部分的千分位
}
1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include <mega16.h>
#include <delay.h>
//
//#ifndef BIT
#define BIT(x) (1 << (x))
//#endif
//数据口:PORTB
#define lcd_data_port PORTC
//一定要用高4位//端口设置
#define LCD_DATA_DDR DDRC
//选中端口
#define LCD_DATA (BIT(4)|BIT(5)|BIT(6)|BIT(7))
#define LCD_RS (BIT(2))
#define LCD_EN (BIT(3))
//封装 置位,清零操作
#define RS_CLR lcd_data_port&=~LCD_RS
#define RS_SET lcd_data_port|=LCD_RS
#define EN_CLR lcd_data_port&=~LCD_EN
#define EN_SET lcd_data_port|=LCD_EN
//#define RW_CLR lcd_data_port&= ~(1 << PB2)
//#define RW_SET lcd_data_port|= (1 << PB2)
//void delay_lcd_us(unsigned int xus);
//void delay_lcd_ms(unsigned int xms);
void lcd_init(void);
void lcd_en_write(void);
void lcd_clear(void);
void lcd_write_com(unsigned char lcd_com); //LCD送命令子函数
void lcd_write_data(unsigned char lcd_data); //LCD送显示数据子函数
void lcd_locate(char x,char y); //显示定位 x是行,y是列
void lcd_string(unsigned char const *DData);//显示字符串
void lcd_1_char(unsigned char data_1_char);//显示一位整数:
void lcd_2_char(unsigned char data_2_char);//显示二位整数:
void lcd_3_char(unsigned int data_3_char); //显示三位整数:
void lcd_4_char(unsigned int data_4_char); //显示四位整数:
void lcd_5_char(unsigned int data_5_char); //显示五位整数:
void lcd_char(unsigned int data_char); //显示任意位的整数
void lcd_float(float f_data); //在1602LCD上显示一个小于100、保留3位小数的浮点数
#endif /* LCD1602_H_ */
|