目前共有1篇帖子。 内容转换:不转换▼
 
点击 回复
600 0
【程序】AVR单片机通过硬件I2C(TWI)读写24C08存储器
一派护法 十九级
1楼 发表于:2017-3-26 23:28
#define F_CPU 11059200

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <util/delay.h>

unsigned char buf[8];
const unsigned char seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
unsigned char id = 0;

void seg_scan(void)
{
    unsigned char i;
    unsigned char n = buf[id];
    for (i = 7; i >= 5; i--)
    {
        PORTC = ~_BV(i);
        PORTA = seg8[n % 10];
        _delay_ms(3);
        PORTA = 0xff;
        n /= 10;
    }

    n = id;
    for (i = 1; i <= 1; i--)
    {
        PORTC = ~_BV(i);
        PORTA = seg8[n % 10];
        _delay_ms(3);
        PORTA = 0xff;
        n /= 10;
    }
}

void read(unsigned char addr)
{
    TWCR |= _BV(TWSTA) | _BV(TWINT); // 开始信号
    while ((TWCR & _BV(TWINT)) == 0); // 等待发送完毕
    TWCR &= ~(_BV(TWSTA) | _BV(TWINT)); // 清除开始信号标志, 同时要保证TWINT未被写1, 以免执行了新的操作
    TWDR = 0xa0; // 器件地址+写信号
    TWCR |= _BV(TWINT); // 开始发送
    while ((TWCR & _BV(TWINT)) == 0); // 等待发送完毕
    TWDR = addr; // 存储单元地址
    TWCR |= _BV(TWINT);
    while ((TWCR & _BV(TWINT)) == 0);
    
    TWCR |= _BV(TWSTA) | _BV(TWINT); // 再次发送开始信号
    while ((TWCR & _BV(TWINT)) == 0);
    TWCR &= ~(_BV(TWSTA) | _BV(TWINT));
    TWDR = 0xa1; // 器件地址+读信号
    TWCR |= _BV(TWINT);
    while ((TWCR & _BV(TWINT)) == 0);

    // 连续读三个字节
    TWCR |= _BV(TWEA) | _BV(TWINT); // TWEA=1: 接收时发送的是应答信号, 告诉器件需要更多数据, TWINT=1: 开始接收
    while ((TWCR & _BV(TWINT)) == 0);
    buf[addr] = TWDR;
    TWCR |= _BV(TWINT);
    while ((TWCR & _BV(TWINT)) == 0);
    buf[addr + 1] = TWDR;
    TWCR &= ~_BV(TWEA); // TWEA=0: 接收的是最后一字节数据, 发送非应答
    while ((TWCR & _BV(TWINT)) == 0);
    buf[addr + 2] = TWDR;
    TWCR |= _BV(TWSTO) | _BV(TWINT); // 结束信号, TWSTO是自动清除的
}

void write(void)
{
    unsigned char i;
    TWCR |= _BV(TWSTA) | _BV(TWINT);
    while ((TWCR & _BV(TWINT)) == 0);
    TWCR &= ~(_BV(TWSTA) | _BV(TWINT)); // 清除TWSTA, 同时要保证TWINT未被写1
    TWDR = 0xa0;
    TWCR |= _BV(TWINT);
    while ((TWCR & _BV(TWINT)) == 0);
    
    TWDR = 0; // 存储单元地址
    TWCR |= _BV(TWINT);
    while ((TWCR & _BV(TWINT)) == 0);

    // 写入8字节数据
    for (i = 0; i < 8; i++)
    {
        TWDR = 100 + i * 10 + i;
        TWCR |= _BV(TWINT);
        while ((TWCR & _BV(TWINT)) == 0);
    }

    // 结束
    TWCR |= _BV(TWSTO) | _BV(TWINT);
    _delay_ms(1); // 等待24C08存储器擦写完毕
}

int main(void)
{
    TWBR = 3;
    TWSR = 2;
    TWCR |= _BV(TWEN); // 开TWI
    write();
    read(5); // 第5~7字节
    read(0); // 第0~2字节
    read(3); // 第3~5字节
    TWCR &= ~_BV(TWEN); // 数码管要占用PC口, 所以将TWI关掉
    
    TIMSK |= _BV(TOIE1); // 开定时器中断
    sei(); // 开总中断
    TCCR1B |= _BV(CS12); // 定时器256分频

    DDRA = DDRC = 0xff;
    while (1)
        seg_scan();
}

ISR(TIMER1_OVF_vect)
{
    id = (id + 1) % sizeof(buf);
}

回复帖子

内容:
用户名: 您目前是匿名发表
验证码:
(快捷键:Ctrl+Enter)
 

本帖信息

点击数:600 回复数:0
评论数: ?
作者:巨大八爪鱼
最后回复:巨大八爪鱼
最后回复时间:2017-3-26 23:28
 
©2010-2024 Arslanbar Ver2.0
除非另有声明,本站采用知识共享署名-相同方式共享 3.0 Unported许可协议进行许可。