 
- UID
- 1029342
- 性别
- 男
|

AVR IO具备多种IO模式:
1 高阻态 ,多用于高阻模拟信号输入,例如ADC数模转换器输入,模拟比较器输入
2 弱上拉状态(Rup=20K~50K),输入用。为低电平信号输入作了优化,省去外部上拉电阻,例如按键输入,低电平中断触发信号输入
3 推挽强输出状态,驱动能力特强(>20mA),可直接推动LED,而且高低驱动能力对称.
使用注意事项:
写用PORTx,读取用PINx
实验时,尽量不要把管脚直接接到GND/VCC,当设定不当,IO口将会输出/灌入 80mA(Vcc=5V)的大电流,导致器件损坏。
作输入时:
1、通常要使能内部上拉电阻,悬空(高阻态)将会很容易受干扰。(表面看好像是51的抗干扰能力强,是因为51永远有内部电阻上拉,)
2、尽量不要让输入悬空或模拟输入电平接近VCC/2,将会消耗太多的电流,特别是低功耗应用场合------CMOS电路的特点
3、如果先前I/O口为输出状态,设置为输入状态后,必须等待1个时钟周期后才能正确的读到外部引脚PINx的值。
4、功能模块(中断,定时器)的输入可以是低电平触发,也可以是上升沿触发或下降沿触发。
5、用于高阻模拟信号输入,切记不要使能内部上拉电阻,影响精确度。例如ADC数模转换器输入,模拟比较器输入
作输出时:
采用必要的限流措施,例如驱动LED要串入限流电阻
复位时:
复位时内部上拉电阻将被禁用。如果应用中(例如电机控制)需要严格的电平控制,请使用外接电阻固定电平。
休眠时:
作输出的,依然维持状态不变
作输入的,一般无效,但如果使能了第二功能(中断使能),其输入功能有效。例如 外部中断的唤醒功能。AVR
的C语言IO操作:
AVR的C语言基于ANSI C,没有像51那样扩展了位操作(布尔操作),虽然汇编指令里面有SBI/CBI/SBIC/SBIS指令, 所以需要采用 位逻辑运算 来实现,这是必须要掌握的。
IO口和功能寄存器的操作方法一样,但对于部分功能寄存器的读写有特殊要求,请参看手册。
不必考虑代码效率的问题,如果可能,GCCAVR会自动优化为SBI/CBI/SBIC/SBIS指令,跟汇编的效率是一样的。
例如 iom16.h 里面定义了 #define PA7 7
(这标准头文件定义了MCU的所有官方定义(包括寄存器,位,中断入口等),但管脚的第二功能没有定义)
想PA7为1 PORTA|=(1<<PA7);
想PA7为0 PORTA&=~(1<<PA7);
想PA7取反 PORTA^=(1<<PA7);
想检测PA7是否为1 if(PINA&(1<<PA7)) { };
想检测PA7是否为0 if!(PINA&(1<<PA7)) { };
* << 为左移运算符,不懂的就要好好复习C语言基础了。
注意IO操作的顺序:
//上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
假设PA口驱动LED的负极,低电平灯亮
初始化方法1:
PORTA=0xFF; //内部上拉,高电平
DDRA=0xFF; //输出高电平---------灯一直是灭的
初始化方法2:
DDRA=0xFF; //输出低电平--------灯被错误点亮了
PORTA=0xFF; //输出高电平--------马上被熄灭了,时间很短(1个指令不到uS时间),灯闪了一下,眼睛无法察觉
但要是这个IO口是控制炸药包的点火信号呢?工控场合要考虑可靠性的问题
模拟OC结构的IIC总线的技巧:
虽然AVR大多带有硬件IIC接口,但也有需要使用软件模拟IIC的情况
可以通过使用外部上拉电阻+控制DDRx的方法来实现OC结构的IIC总线。
AVR单片机I/O口结构分析
IIC的速度跟上拉电阻有关,内部的上拉电阻阻值较大(Rup=20K~50K),只能用于低速的场合
#defineSDA 0 //PC0
#defineSCL 1 //PC1
(程序初始化设定 SDA和SCL都是 PORT=0,DDR=0)
#defineSDA_0() DDRA|=(1<<SDA) //输出低电平
#defineSDA_1() DDRA&=~(1<<SDA) //输入,外部电阻上拉为高电平
#defineSCL_0() DDRA|=(1<<SCL) //输出低电平
#defineSCL_1() DDRA&=~(1<<SCL) //输入,外部电阻上拉为高电平
使用上面的SDA_0()/SDA_1()/SCL_0()/SCL_1()宏即可,直观,而且效率跟汇编是一样的 |
|