[AVR单片机]

利用TWI与PCF8591通信读取AD采样值问题

[复制链接]
1719|3
手机看帖
扫描二维码
随时随地手机跟帖
黄喉|  楼主 | 2014-7-22 17:43 | 显示全部楼层 |阅读模式
闲着蛋疼,Mega128本身自带AD,但是由于还处在学习阶段,于是用TWI与PCF8591进行通信,利用PCF8591读取ADC采样电压值,调节电位器,明明最大值是5V才对呀,可是扭开发板的电位器,电压从0V调节到2.5V,再变成0V,再往上调,最大才2.42V。调用的读函数用在24C02上可以正常读出数值。想了半天不知道哪里有问题。请高手帮忙看看!!!万分感谢,我是菜鸟初学者,还望高手不吝赐教


#include<iom128v.h>
#include<macros.h>
#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF

#define AddWr          0x90
#define AddRd          0x91

//MT模式:主机发送模式
#define START                             0x08
#define RE_START                    0x10
#define MT_SLA_ACK                  0x18
#define MT_SLA_NOACK          0x20
#define MT_DATA_ACK                  0x28
#define MT_DATA_NOACK         0x30

//MR模式:主机接收模式
#define START                          0x08
#define RE_START                0x10
#define MR_SLA_ACK                0x40
#define MR_SLA_NOACK        0x48
#define MR_DATA_ACK                0x50
#define MR_DATA_NOACK        0x58

unsigned char TempData[];
unsigned char DuanMa[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
unsigned char WeiMa[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

unsigned char ReadAdcFlag;

#define START_I2C()                {TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);}
#define STOP_I2C()                {TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);}
#define WAIT()                        {while (!(TWCR & (1<<TWINT)));}
#define TWI()                        {TWCR = (1<<TWINT)|(1<<TWEN);}
#define SendByte(X)                {TWDR = X;        TWCR = (1<<TWINT) | (1<<TWEN);}

void Delayus(unsigned int US)                  
{
     unsigned int i;
     US=US*5/4;                           
     for( i=0;i<US;i++);
}

void Delayms(unsigned int MS)                  
{
     unsigned int i,j;
     for( i=0;i<MS;i++)
     for(j=0;j<1141;j++);       
}

void Led_init(void)
{
         DDRA = 0xff;
         DDRF |= (1 << 3);
         
         PORTA = 0xff;
         PORTF |= (1 << 3);
         PORTF &= ~(1 << 3);
}

void Seg_init(void)
{
         DDRA = 0xff;
         DDRC = 0xff;
         DDRF |= ((1 << 1) | (1 << 2));
         
         PORTC = 0xff;
         PORTF |= (1 << 1);
         PORTF &= ~(1 << 1);
         
         PORTA = 0xff;
         PORTF |= (1 << 2);
         PORTF &= ~(1 << 2);
}

void Seg_Display(unsigned char firstbit,unsigned char weishu)
{
         static unsigned char i;
         PORTC = 0xff;                                                             //数码管消隐
         PORTF |= BIT(1);
         PORTF &= ~BIT(1);
       
         PORTC = TempData[i];
         PORTF |= BIT(1);
         PORTF &= ~BIT(1);

         PORTA = WeiMa[i+firstbit];
         PORTF |= BIT(2);
         PORTF &= ~BIT(2);
         Delayms(1);
         i++;
         if(i == weishu)
                   i = 0;
}

unsigned char RevADC(unsigned char Channal)
{
        unsigned char Val;
       
        START_I2C(); //发出START 信号
        WAIT(); //等待TWINT 置位, TWINT 置位表示START 信号已发出
        if ((TWSR & 0xF8) != START) //检验TWI 状态寄存器,屏蔽预分频位,如果状态字不是START 转出错处理
           return 0;
       
        SendByte(AddWr); //将SLA_W 载入TWDR 寄存器, TWINT位清零,启动发送地址
        WAIT(); //等待TWINT 置位, TWINT 置位表示总线命令SLA+W 已发出,及收到应答信号ACK/NACK
        if ((TWSR & 0xF8) != MT_SLA_ACK) //检验TWI 状态寄存器,屏蔽预分频位,如果状态字不是MT_SLA_ACK 转出错处理
           return 0;
          
        SendByte(0x40 | Channal);
        WAIT(); //等待TWINT 置位, TWINT 置位表示总线命令已发出,及收到应答信号ACK/NACK
        if ((TWSR & 0xF8) != MT_DATA_ACK) //检验TWI 状态寄存器
           return 0;
                  
        START_I2C(); //发出START 信号
        WAIT(); //等待TWINT 置位, TWINT 置位表示START 信号已发出
        if ((TWSR & 0xF8) != RE_START) //检验TWI 状态寄存器,屏蔽预分频位,如果状态字不是START 转出错处理
           return 0;

        SendByte(AddRd); //将SLA_W 载入TWDR 寄存器, TWINT位清零,启动发送地址
        WAIT(); //等待TWINT 置位, TWINT 置位表示总线命令SLA+R 已发出,及收到应答信号ACK/NACK
        if ((TWSR & 0xF8) != MR_SLA_ACK) //检验TWI 状态寄存器,屏蔽预分频位,如果状态字不是MR_SLA_ACK 转出错处理
           return 0;                       
                               
        TWI(); //启动主I2C读方式
        WAIT(); //等待TWINT 置位,及收到应答信号ACK/NACK
        if ((TWSR & 0xF8) != MR_DATA_NOACK)
           return 0;        
                                          
        Val = TWDR;
        STOP_I2C();
        return Val;
}

void Timer1_init(void)
{
         TCCR1B = 0x00; //stop
         TCNT1H = 0xFD; //setup
         TCNT1L = 0x8F;
         TCCR1B = 0x03; //start Timer
         TIMSK = 0x04; //timer interrupt sources
         SREG |= (1 << 7);
}

void main(void)
{
         unsigned int num;
         
         Led_init();
         Seg_init();
         Timer1_init();
         while(1)
                 {
                          num = RevADC(0);
                         num = (num * 100 * 5)/255;
                         
                         TempData[0] = DuanMa[num / 100] & 0x7f;
                         TempData[1] = DuanMa[(num % 100) / 10];
                         TempData[2] = DuanMa[num % 100 % 10];
                }
}

void timer1_ovf_isr(void)
{
         //TIMER1 has overflowed
         TCNT1H = 0xFD; //reload counter high value
         TCNT1L = 0x8F; //reload counter low value
         Seg_Display(0,3);
}

相关帖子

wangch_sh| | 2014-7-22 19:22 | 显示全部楼层
用示波器看波形,对时序。

使用特权

评论回复
黄喉|  楼主 | 2014-7-23 09:01 | 显示全部楼层
wangch_sh 发表于 2014-7-22 19:22
用示波器看波形,对时序。

该读函数可以正常读取24C02数据,所以时序上应该不是问题吧

使用特权

评论回复
bayueyun| | 2016-4-20 15:08 | 显示全部楼层
您好,请问您解决了吗,我也是用pcf8591采集电压,之前正常,后来模块烧过一次,换过之后采集到的数据就是不正常,不知道什么问题。急求

使用特权

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

本版积分规则

10

主题

35

帖子

1

粉丝