打印
[AVR单片机]

求助:用CVAVR,使用1602显示AD采样的电压,显示异常

[复制链接]
1485|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一颗心的思考|  楼主 | 2014-12-26 18:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用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_ */


相关帖子

沙发
wangch_sh| | 2014-12-27 08:43 | 只看该作者
把换算成电压值放在中断外头。

使用特权

评论回复
板凳
一颗心的思考|  楼主 | 2014-12-27 12:13 | 只看该作者
wangch_sh 发表于 2014-12-27 08:43
把换算成电压值放在中断外头。

为什么?不是TO的问题吗?没写T0的匹配中断函数。所以出错。正在分析原因。

使用特权

评论回复
地板
一颗心的思考|  楼主 | 2014-12-27 12:17 | 只看该作者
wangch_sh 发表于 2014-12-27 08:43
把换算成电压值放在中断外头。

允许了T0的匹配中断,但是没写T0的中断处理函数。

使用特权

评论回复
5
wangch_sh| | 2014-12-27 12:33 | 只看该作者
// ADC 转换完成中断服务
interrupt [ADC_INT] void adc_isr(void)
{   

    adc_data=ADCW;                  //读取ADC置换结果                  
    adc_v=(unsigned long)adc_data*2560/1024;    //换算成电压值

}
这一个。

使用特权

评论回复
6
一颗心的思考|  楼主 | 2014-12-27 12:43 | 只看该作者
wangch_sh 发表于 2014-12-27 12:33
// ADC 转换完成中断服务
interrupt [ADC_INT] void adc_isr(void)
{   

能解释以下原因吗

使用特权

评论回复
7
一颗心的思考|  楼主 | 2014-12-27 12:52 | 只看该作者
wangch_sh 发表于 2014-12-27 12:33
// ADC 转换完成中断服务
interrupt [ADC_INT] void adc_isr(void)
{   

已经成功。我认为主要问题是:使用T0的匹配作为ADC转换的触发源,但是多此一举错误开启了T0的中断,而且没有写T0的匹配中断函数,所以,导致一直出不来。

使用特权

评论回复
8
一颗心的思考|  楼主 | 2014-12-27 12:55 | 只看该作者
.C
/*********************************************
File name           : demo_6_8.c
Chip type           : ATmega16
Program type        : Application
Clock frequency     : 4.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*********************************************/
#include <mega16.h>
#include <delay.h>
#include "lcd1602.h"
//
#asm
.equ __lcd_port=0x15         ; PORTC数据寄存器地址
#endasm
/*  [LCD]     
    1 GND- 9  GND
    2 +5V- 10 VCC  
    3 VLC- LCD HEADER Vo
    4 RS - 1  PC0 (M16)
    5 RD - 2  PC1 (M16)
    6 EN - 3  PC2 (M16)
   11 D4 - 5  PC4 (M16)
   12 D5 - 6  PC5 (M16)
   13 D6 - 7  PC6 (M16)
   14 D7 - 8  PC7 (M16) */
unsigned int adc_data,adc_v;
interrupt [ADC_INT] void adc_isr(void)
{   

    adc_data=ADCW;                  //读取ADC置换结果                  
    adc_v=(unsigned long)adc_data*2560/1024;    //换算成电压值
  
}
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
          ;
}
void main(void)
{
//        unsigned char flash *str;
//        str = dis_str;
        lcd_init(16);                                // initialize the LCD for 2 lines & 16 columns     
    DDRA=0x00;
    PORTA=0x00;               
    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

  #asm("sei")     // 开放全局中断
        while(1)
        {
                lcd_gotoxy(0,0);                                // clere the LCD   
        lcd_4_char(adc_v);
                //lcd_putsf("It's demo_6_8.c");        // display the message
            lcd_gotoxy(0,1);                                // go on the second LCD line
        lcd_3_char(339);   
        lcd_float(52.9) ;  
            //delay_ms(500);
    }       
}


#include "lcd1602.h"
void lcd_1_char(unsigned char data_1_char)         //在1602LCD上显示一个1位的整数
{                unsigned char lcd_table[2];
               
                lcd_table[1]=data_1_char%10;       //获得个位的数字   
                lcd_putchar(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_putchar(lcd_table[1]+0x30); //显示十位     
                lcd_putchar(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_putchar(lcd_table[1]+0x30); //显示百位     
                lcd_putchar(lcd_table[2]+0x30); //显示十位     
                lcd_putchar(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_putchar(lcd_table[1]+0x30); //显示千位
                 lcd_putchar(lcd_table[2]+0x30); //显示百位     
                 lcd_putchar(lcd_table[3]+0x30); //显示十位     
                 lcd_putchar(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_putchar(lcd_table[1]+0x30); //显示万位
                  lcd_putchar(lcd_table[2]+0x30); //显示千位
                  lcd_putchar(lcd_table[3]+0x30); //显示百位     
                  lcd_putchar(lcd_table[4]+0x30); //显示十位     
                 lcd_putchar(lcd_table[5]+0x30); //显示个位
}
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_putchar(' '); //如果整数部分的十位数是0则不显示(显示空格)
                        else  lcd_putchar(lcd_table[0]+0x30); //显示整数部分的十位数,加上0x30以便直接得到相应的ASCII码去显示
                 lcd_putchar(lcd_table[1]+0x30); //显示整数部分的个位数
                 lcd_putchar('.');                            //显示小数点"."         
                 lcd_putchar(lcd_table[2]+0x30); //显示小数部分的十分位     
                 lcd_putchar(lcd_table[3]+0x30); //显示小数部分的百分位     
                 lcd_putchar(lcd_table[4]+0x30); //显示小数部分的千分位
}


#ifndef __LCD1602_H__
#define __LCD1602_H__

#include <mega16.h>
#include <delay.h>
#include <lcd.h>
/*
  lcd_gotoxy();
  lcd_putsf();
lcd_putsf("It's demo_6_8.c");                          ;PORTC数据寄存器地址
    lcd_clear();          
   
     lcd_float() ;  
*/   



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_float(float f_data) ;         
#endif /* LCD1602_H_ */

使用特权

评论回复
9
wangch_sh| | 2014-12-27 14:09 | 只看该作者
那恭喜了。

使用特权

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

本版积分规则

13

主题

104

帖子

0

粉丝