我正在将ATTINY85 MCU与2线从模式的USI一起使用。使用i2cdetect
和i2cset
之类的Linux工具,我已经使用RPi4验证了以下内容:
-
i2cdetect
在0x05地址i2cdetect -y 1
上检测到设备 - 设备正确发送了ACK位
-
i2cset
在写入期间未显示错误迹象:i2cset -y 1 0x05 0x01
我想帮助您弄清楚为什么USIDR没有将0x01返回到我的LED变量,从而打开/关闭LED
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
typedef enum
{
ADDRESS_MATCH = 0x00,READ_DATA = 0x01,SEND_ACK = 0x02,} USI_State_t;
volatile USI_State_t state;
volatile int8_t LED;
int main(void)
{
PORTB |= (1<<PB0) | (1<<PB2); //PB0=SDA,PB2 = SCL
DDRB &= ~(1<<PB0) | ~(1<<PB2);
DDRB |= (1<<PB4);
USICR = (1<<USISIF) | (0<<USIOIF) | (1<<USIWM1) | (0<<USIWM0) | (1<<USICS1) | (0<<USICS0) | (0<<USICLK) | (0<<USITC);
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | (1<<USIDC) | 0x00;
sei();
while (1)
{
if (LED != (int8_t)0x00) PORTB |= (1<<PB4);
else PORTB &= ~(1<<PB4);
}
}
ISR(USI_START_vect)
{
DDRB &= ~(1<<PB0);
while ((PINB & (1<<PB2)) && !(PINB & (1<<PB0)));
if (!(PINB & (1<<PB0)))
{
USICR = (1<<USISIF) | (1<<USIOIF) | (1<<USIWM1) | (1<<USIWM0) | (1<<USICS1) | (0<<USICS0) | (0<<USICLK) | (0<<USITC);
}
else USICR = (1<<USISIF) | (0<<USIOIF) | (1<<USIWM1) | (0<<USIWM0) | (1<<USICS1) | (0<<USICS0) | (0<<USICLK) | (0<<USITC);
state = ADDRESS_MATCH;
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | (1<<USIDC) | 0x00;
}
ISR(USI_OVF_vect)
{
switch (state)
{
case ADDRESS_MATCH:
if ((USIDR>>1) != 0x05)
{
DDRB &= ~(1<<PB0);
USICR = (1<<USISIF) | (0<<USIOIF) | (1<<USIWM1) | (0<<USIWM0) | (1<<USICS1) | (0<<USICS0) | (0<<USICLK) | (0<<USITC);
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | (1<<USIDC) | 0x00;
}
else
{
state = READ_DATA;
USIDR = 0x00;
DDRB |= (1<<PB0);
USISR = (0<<USISIF) | (1<<USIOIF) | (1<<USIPF) | (1<<USIDC) | 0x0E;
}
break;
case READ_DATA:
DDRB &= ~(1<<PB0);
state = SEND_ACK;
USISR = (0<<USISIF) | (1<<USIOIF) | (1<<USIPF) | (1<<USIDC) | 0x00;
break;
case SEND_ACK:
LED = (int8_t)USIDR;
USIDR = 0x0;
DDRB |= (1<<PB0);
USISR = (0<<USISIF) | (1<<USIOIF) | (1<<USIPF) | (1<<USIDC) | 0x0E;
break;
}
}
LED变量设置为switch语句SEND_ACK内部的值。任何帮助将不胜感激!