内容包括AVRStudio及WinAVR介绍,软件下载地址,编译环境设置,IAR for AVR的使用,AVR单片机的介绍。紫色文字是超链接,点击自动跳转至相关博文。持续更新,原创不易!
目录:
一、AVRStudio及WinAVR简介
1、使用AVR GCC做为编译器
2、选择仿真调试平台
3、选择Device,设置Frequency,代码优化选项Optimization,输出hex文件
4、设置包含文件(头文件)路径
5、设置库文件路径
6、设置工具链路径(不使用AVR Toolchain)
二、Avr Studio和Winavr最新版下载地址
三、Avr Studio和Winavr编译环境设置
四、IAR for AVR的使用(CC2530开发套件zigbee开发板)
1、出现“IAR AVR unknown or ambiguous symbol.main”
2、处于调试状态,但是不能在C语言上单步运行,也不能设置断点
3、IAR For AVR软件的精确延时
4、IAR中加入编译所需库的头文件
五、AVR JTAG ICE MKII仿真器
六、AVR寄存器定义
七、AVR移位算法详细解释(1<<X)
——————————————————————————————————
一、AVRStudio及WinAVR简介
AVRStudio 是ATMEL 官方针对AVR 系列单片机推出的集成开发环境,它集开发调试于一体,有很好的用户界面,很好的稳定性。AVRSdudio 是免费的。AVRStudio 本身可以开发汇编程序,如果希望使用C语言开发,则需要安装C编译器(WinAVR 等)。
WinAVR 是GNU 组织推出的AVR 单片机的gcc 编译器,该编译器的编译效率极高。gcc 编译器是开源的,是免费的。使用gcc 编译器,可以掌握标准c 的语法等,为学习Linux 等奠定基础。
——————————————————————————————————
二、Avr Studio和Winavr最新版下载地址
AVRStudio 最新版本的官方下载地址:Smart | Connected | Secure | Microchip Technology
WinAVR 最新版本的官方下载地址:WinAVR – Browse Files at SourceForge.net
——————————————————————————————————
三、Avr Studio和Winavr编译环境设置
—————————————
—————————————
3、选择Device,设置Frequency,代码优化选项Optimization,输出hex文件
—————————————
—————————————
—————————————
6、设置工具链路径(不使用AVR Toolchain) 如此便可使用winavr作为c编译器,不会出现avr-objcopy: '****.elf': No such file的错误。
—————————————————————————————————— 四、IAR for AVR的使用(CC2530开发套件zigbee开发板)
1、出现“IAR AVR unknown or ambiguous symbol.main”
project==>options==>linker,format设置成debug。
IAR下必须进入DEBUG模式才能进行调试,如果不连接开发工具的话,断点也是不行的
—————————————
2、处于调试状态,但是不能在C语言上单步运行,也不能设置断点
project==>options==>C/C++Compiler,将Generate debug information打上勾。
—————————————
3、IAR For AVR软件的精确延时
不浪费中断的情况下的精确延时当然是软件自带的单周期的空操作,比如_nop_();
在IAR for AVR中的库函数#include"intrinsics.h"里面有个单周期的延时函数__delay_cycles();(相当于_nop_();),
如果__delay_cycles(100)就是100个mclk的周期延时。
然后就是下面的操作了:
#ifndef __delay_h
#define __delay_h
#include"intrinsics.h"
#define xtal 8 //这里就是你要使用的晶振的频率(单位NHZ)
#define delay_us(x) __delay_cycles((unsigned long)(x*xtal))
#define delay_ms(x) __delay_cycles((unsigned long)(x*xtal*1000))
#define delay_s(x) __delay_cycles((unsigned long)(x*xtal*1000000))
#endif
3)就是在你用到延时的函数里面调用#include"Delay.h"(这里是不区分大小写的,哈,不用担心这个)
这就在不浪费中断情况下的软件延时,当然你要非得精确,那非得定时计数器不可了
补充一下:
我用的是IAR for AVR,别的软件什么的似乎也有延时函数,如果没有可以用下面的这个延时(听说也是相当准的,在8MHZ晶振下,不管是外接还是内部晶振,哈都一样):
//——————————————————————————
//延时函数
void delay_ms(uint k)
{
uint i,j;
for(i=0;i
for(j=0;j<1140;j++);
}
还有一个:差点忘记(这个不知道是那个哥们想到的,也可以改变晶振的~~~都贴出来,反正没事干):
//——————————————————————————
//延时1ms的函数,没有参数传递
void delay_1ms()
{
uint i;
for(i=1;i<(uint)(xtal*143-2);i++)
;
}
//——————————————————————————
//延时nms的函数,有参数传递
void delay_nms(uint n)
{
uint i=0;
while(i
{
delay_1ms();
i++;
}
}
—————————————
4、IAR中加入编译所需库的头文件
工程名右击->options->C/C++ compiler->Preprocessor中填入头文件所在的目录即可,$PROJ_DIR$表示工程所在目录,\..\工程所在目录的上一层目录。设置后详见图片。
——————————————————————————————————
五、AVR JTAG ICE MKII仿真器
注意:此处的VTref需要接VCC。
——————————————————————————————————
六、AVR寄存器定义
#include "iom16v.h"
#include "macros.h"
void initialize()
{
// DDRx端口方向寄存器,PORTx数据寄存器,PINx输入引脚寄存器
// DDRxn相应位为1,引脚为输出否则为输入
// PORTxn为1时,上拉电阻使能
DDRA = 0x00;
}
void init_adc()
{
// ADMUX
// —————————————————————–
// | REFS1 | REFS0 | ADLAR | MUX4 | MUX3 | MUX2 | MUX1 | MUX0 |
// —————————————————————–
// REFS1 REFS0: 00,使用AREF,内部参考电压关闭
// 01,AVCC、AREF引脚外加滤波电容
// 10,保留
// 11,2.56V片内基准电压,AREF引脚外加滤波电容
// ADLAR: ADC转换结果左对齐
// MUX4 ~ MUX0 单端输入 正差分输入 负差分输入 增益
// 00000 ~ 00111 ADC0~ADC7
// 01000 ADC0 ADC0 10x
// 01001 ADC1 ADC0 10x
// 01010 ADC0 ADC0 200x
// 01011 ADC1 ADC0 200x
// 01100 ADC2 ADC2 10x
// 01101 ADC3 ADC2 10x
// 01110 ADC2 ADC2 200x
// 01111 ADC3 ADC2 200x
// 10000 ADC0 ADC1 1x
// 10001 ADC1 ADC1 1x
// 10010 ADC2 ADC1 1x
// 10011 ADC3 ADC1 1x
// 10100 ADC4 ADC1 1x
// 10101 ADC5 ADC1 1x
// 10110 ADC6 ADC1 1x
// 10111 ADC7 ADC1 1x
// 11000 ADC0 ADC2 1x
// 11001 ADC1 ADC2 1x
// 11010 ADC2 ADC2 1x
// 11011 ADC3 ADC2 1x
// 11100 ADC4 ADC2 1x
// 11101 ADC5 ADC2 1x
// 11110 1.23V(VBG)
// 11111 0V(GND)
ADMUX = 0;
// ADCSRA
// —————————————————————–
// | ADEN | ADSC | ADFR | ADIF | ADIE | ADPS2 | ADPS1 | ADPS0 |
// —————————————————————–
// ADEN:ADC使能,转换过程中禁止ADC则立即中止转换。
// ADSC:ADC开始转换。在转换过程中ADSC为1直到转换结束。
// ADFR:是否工作在连续模式,该位写0,停止连续转换模式。
// ADIF:ADC中断标志。中断服务硬件清零。
// ADIE:ADC中断使能
// ADSP2 ~ ADSP0:ADC预分频选择 000:2分频,001到111为2到128分频
// ADC在50~200KHz时钟时能获得最大精度
ADCSRA = 0;
// ADCC & ADCH
// ADC转换结果寄存器,差分通道结果以2的补码形式表示,ADC数据必须读过
// ADCH后才可进行数据更新。对于精度小于8位的左对齐数据可只读ADCH。
// 数据右对齐(ADLAR = 0)
// ADCH————————————————————-
// | – | – | – | – | – | – | ADC9 | ADC8 |
// —————————————————————–
// ADCL————————————————————-
// | ADC7 | ADC6 | ADC5 | ADC4 | ADC3 | ADC2 | ADC1 | ADC0 |
// —————————————————————–
//
}
void init_timer()
{
//SFIOR
// —————————————————————–
// | TSM | – | – | – | ACME | PUD | PSR0 | PSR321|
// —————————————————————–
// TSM: T/C同步模式。置位时,PSR0和PSR321保持其数据直到被更新或TSM被清零
// PSR0:T/C0预分频器复位,置位时使预频器复位,直到为0时表示复位完成
// PSR321: T/C3、2、1预分频繁器复位,此位读总为0
// ACME: 模拟比较器使能
// PUD:所有端口上拉电阻禁止,置1为禁止
SFIOR = 0;
}
void init_timer0()
{
//TCCR0 T/C0控制寄存器
// —————————————————————–
// | FOC0 | WGM00 | COM01 | COM00 | WGM01 | CS02 | CS01 | CS00 |
// —————————————————————–
// FOC0:强制输出比较启动
// WGM01, WGM00: 工作模式选择
// 00:普通模式,01:PWM相位修正,
// 10:比较匹配时清除计数器模式(CTC模式),11:快速PWM
// COM01, COM00:比较匹配时的输出模式
// WGMxx为普通模式或CTC模式时
// 00:OC0未连接,
// 01:OC0取反,
// 10:OC0清零,
// 11:OC0置位
// WGMxx为相位修正PWM模式
// 00:OC0未连接,
// 01:保留,
// 10:升序匹配时清零OC0;降序匹配时置位OC0,
// 11:升序匹配时置位OC0;降序匹配时清零OC0
// WGMxx为快速PWM模式
// 00:OC0未连接
// 01:保留
// 10:匹配时OC0清零;计数到TOP时OC0置位
// 11:匹配时OC0置位;计数到TOP时OC0清零
// CS02,CS01,CS00:T/C0时钟预分频选择
// 000:无时钟,T/C不工作 001:1/1
// 010:1/8 011:1/32 100:1/64
// 101:1/128 110:1/256 111:1/1024
TCCR0 = 0;
//TCNT0 T/C0计数寄存器,8位
//OCR0 输出比较寄存器,8位
//TIMSK T/C中断屏蔽寄存器
// —————————————————————–
// | OCIE2 | TOIE2 | TICIE1| OCIE1A| OCIE1B| TOIE1 | OCIE0 | TOIE0 |
// —————————————————————–
// OCIE2:T/C2输出比较匹配中断使能
// TOIE2:T/C2溢出中断使能
// TICIE1:T/C1输入捕捉中断使能
// OCIE1A:T/C1输出比较A匹配中断使能
// OCIE1B:T/C1输出比较B匹配中断使能
// TOIE1:T/C1溢出中断使能
// OCIE0:T/C0输出比较匹配中断使能
// TOIE0:T/C0溢出中断使能
TIMSK = 0;
//ETIMSK T/C扩展中断屏蔽寄存器
// —————————————————————–
// | – | – | TICIE3| OCIE3A| OCIE3B| TOIE3 | OCIE3C| OCIE1C|
// —————————————————————–
// TICIE3:T/C3输入捕捉中断使能
// OCIE3A:T/C3输出比较A匹配中断使能
// OCIE3B:T/C3输出比较B匹配中断使能
// TOIE3:T/C3溢出中断使能
// OCIE3C:T/C3输出比较C匹配中断使能
// OCIE1C:T/C1输出比较C匹配中断使能
ETIMSK = 0;
//TIFR T/C中断标志寄存器
// —————————————————————–
// | OCF2 | TOV2 | ICF1 | OCF1A | OCF1B | TOV1 | OCF0 | TOV0 |
// —————————————————————–
// OCF2:T/C2输出比较匹配标志
// TOV2:T/C2溢出标志
// ICF1:T/C1输入捕捉标志位
// OCF1A:T/C1输出比较A匹配标志位
// OCF1B:T/C1输出比较B匹配标志位
// TOV1:T/C1溢出标志
// OCF0:T/C0输出比较匹配标志
// TOV0:T/C0溢出标志
//ETIFR 扩展的T/C中断标志寄存器
// —————————————————————–
// | – | – | ICF3 | OCF3A | OCF3B | TOV3 | OCF3C | OCF1C |
// —————————————————————–
// ICF3:T/C3输入捕捉匹配标志位
// OCF3A:T/C3输出比较A匹配标志位
// OCF3B:T/C3输出比较B匹配标志位
// TOV3:T/C3溢出标志位
// OCF3C:T/C3输出比较C匹配标志位
// OCF1C:T/C1输出比较C匹配标志位
//ASSR T/C0异步状态寄存器
// —————————————————————–
// | – | – | – | – | AS0 | TCN0UB| OCR0UB| TCR0UB|
// —————————————————————–
// AS0:T/C0使用外部时钟
// TCN0UB:TCNT0更新中,写TCNT0时将置位,为0时表明TCNT0可以写入新值
// OCR0UB:OCR0更新中,写OCR0时将置位,为0表明OCR0可以写入新值
// TCR0UB:TCCR0更新中,写TCCR0时将置位,为0表明TCCR0可以写入新值
ASSR = 0;
}
void init_timer2()
{
//TCCR2 T/C2控制寄存器
// —————————————————————–
// | FOC2 | WGM20 | COM21 | COM20 | WGM21 | CS22 | CS21 | CS20 |
// —————————————————————–
// FOC2:强制输出比较启动
// WGM21, WGM20: 工作模式选择
// 00:普通模式,01:PWM相位修正,
// 10:比较匹配时清除计数器模式(CTC模式),11:快速PWM
// COM21, COM20:比较匹配时的输出模式
// WGMxx为普通模式或CTC模式时
// 00:OC0未连接,
// 01:OC0取反,
// 10:OC0清零,
// 11:OC0置位
// WGMxx为相位修正PWM模式
// 00:OC0未连接,
// 01:保留,
// 10:升序匹配时清零OC0;降序匹配时置位OC0,
// 11:升序匹配时置位OC0;降序匹配时清零OC0
// WGMxx为快速PWM模式
// 00:OC0未连接
// 01:保留
// 10:匹配时OC0清零;计数到TOP时OC0置位
// 11:匹配时OC0置位;计数到TOP时OC0清零
// CS22,CS21,CS20:T/C0时钟预分频选择
// 000:无时钟,T/C不工作 001:1/1
// 010:1/8 011:1/32 100:1/64
// 101:1/128 110:1/256 111:1/1024
TCCR2 = 0;
//TCNT2 T/C2计数寄存器,8位
//OCR2 T/C2比较寄存器,8位
}
void init_timer1()
{
//TCCR1A T/C1控制寄存器A
// —————————————————————–
// | COM1A1| COM1A0| COM1B1| COM1B0| COM1C1| COM1C0| WGM11 | WGM10 |
// —————————————————————–
//TCCR1B T/C1控制寄存器B
// —————————————————————–
// | ICNC1 | ICES1 | – | WGM13 | WGM12 | CS12 | CS11 | CS10 |
// —————————————————————–
//TCCR1C T/C1控制寄存器C
// —————————————————————–
// | FOC1A | FOC1B | FOC1C | – | – | – | – | – |
// —————————————————————–
// COM1A1,COM1A0:通道A的比较输出模式
// COM1B1,COM1B0:通道B的比较输出模式
// COM1C1,COM1C0:通道C的比较输出模式
// WGM13,WGM12,WGM11,WGM10:波型发生模式:
// 比较输出模式(CTC模式),非PWM
// 00 普通端口操作,OC1A/OC1B/OC1C未连接
// 01 比较匹配时OC1A/OC1B/OC1C电平取反
// 10 比较匹配时清零OC1A/OC1B/OC1C(输出低电平)
// 11 比较匹配时置位OC1A/OC1B/OC1C(输出高电平)
// 比较输出模式(CTC模式),快速PWM
// 00 普通端口操作,OC1A/OC1B/OC1C未连接
// 01 WGM13为0时同上,为1时比较匹配时 OC1A电平取反,OC1B/OC1C保留
// 10 比较匹配时OC1A/OC1B/OC1C清零,在TOP时OC1A/OC1B/OC1C置位
// 11 比较匹配时OC1A/OC1B/OC1C置位,在TOP时OC1A/OC1B/OC1C清零
// 比较输出模式(CTC模式),相位修正及相频修正PWM
// 00 普通端口操作,OC1A/OC1B/OC1C未连接
// 01 WGM13为0:同上,为1时比较匹配时 OC1A电平取反,OC1B/OC1C保留
// 10 升序计数匹配时将OC1A/OC1B/OC1C清零,降序计数匹配时将OC1A/OC1B/OC1C置位
// 11 升序计数匹配时将OC1A/OC1B/OC1C置位,降序计数匹配时将OC1A/OC1B/OC1C清零
//
// 模式 WGM1x 工作模式说明 TOP OCR1x更新时刻 TOVn置位时刻
// 0 0000 普通模式 0xFFFF 立即 MAX
// 1 0001 8位相位修正PWM 0x00FF TOP BOTTOM
// 2 0010 9位相位修正PWM 0x01FF TOP BOTTOM
// 3 0011 10位相位修正PWM 0x03FF TOP BOTTOM
// 4 0100 CTC OCRnA 立即 MAX
// 5 0101 8位快速PWM 0x00FF TOP TOP
// 6 0110 9位快速PWM 0x01FF TOP TOP
// 7 0111 10位快速PWM 0x03FF TOP TOP
// 8 1000 相位频率修正PWM ICRn BOTTOM BOTTOM
// 9 1001 相位频率修正PWM OCRnA BOTTOM BOTTOM
// 10 1010 相位修正PWM ICRn TOP BOTTOM
// 11 1011 相位修正PWM OCRnA TOP BOTTOM
// 12 1100 CTC ICRn 立即 MAX
// 13 1101 保留 – – –
// 14 1110 快速PWM ICRn TOP TOP
// 15 1111 快速PWM OCRnA TOP TOP
// ICNC1:使能/禁止输入捕捉噪声抑制器
// ICES1:输入捕获触发沿选择,0为下降沿触发,1为上升沿触发
// CS12,CS11,CS10:T/C0时钟预分频选择
// 000:无时钟,T/C不工作 001:1/1
// 010:1/8 011:1/64 100:1/256
// 101:1/1024 110:外部T1脚下降沿驱动 111:外部T1脚上升沿驱动
// FOC1A,FOC1B,FOC1C:强制输出比较通道A,B,C
TCCR1A = TCCR1B = TCCR1C = 0;
//TCNT1H,TCNT1L 定时/计数器1
//OCR1AH,OCR1AL 输出比较寄存器1A
//OCR1BH,OCR1BL 输出比较寄存器1B
//OCR1CH,OCR1CL 输出比较寄存器1C
//ICR1H,ICR1L 输入捕捉寄存器1
}
void init_timer3()
{
//TCCR3A T/C3控制寄存器A
// —————————————————————–
// | COM3A1| COM3A0| COM3B1| COM3B0| COM3C1| COM3C0| WGM31 | WGM30 |
// —————————————————————–
//TCCR3B T/C3控制寄存器B
// —————————————————————–
// | ICNC3 | ICES3 | – | WGM33 | WGM32 | CS32 | CS31 | CS30 |
// —————————————————————–
//TCCR3C T/C3控制寄存器C
// —————————————————————–
// | FOC3A | FOC3B | FOC3C | – | – | – | – | – |
// —————————————————————–
// COM3A1,COM3A0:通道A的比较输出模式
// COM3B1,COM3B0:通道B的比较输出模式
// COM3C1,COM3C0:通道C的比较输出模式
// WGM33,WGM32,WGM31,WGM30:波型发生模式:
// 比较输出模式(CTC模式),非PWM
// 00 普通端口操作,OC3A/OC3B/OC3C未连接
// 01 比较匹配时OC3A/OC3B/OC3C电平取反
// 10 比较匹配时清零OC3A/OC3B/OC3C(输出低电平)
// 11 比较匹配时置位OC3A/OC3B/OC3C(输出高电平)
// 比较输出模式(CTC模式),快速PWM
// 00 普通端口操作,OC3A/OC3B/OC3C未连接
// 01 WGM13为0时同上,为1时比较匹配时 OC3A电平取反,OC3B/OC3C保留
// 10 比较匹配时OC3A/OC3B/OC3C清零,在TOP时OC3A/OC3B/OC3C置位
// 11 比较匹配时OC3A/OC3B/OC3C置位,在TOP时OC3A/OC3B/OC3C清零
// 比较输出模式(CTC模式),相位修正及相频修正PWM
// 00 普通端口操作,OC3A/OC3B/OC3C未连接
// 01 WGM13为0:同上,为1时比较匹配时 OC3A电平取反,OC3B/OC3C保留
// 10 升序计数匹配时将OC3A/OC3B/OC3C清零,降序计数匹配时将OC3A/OC3B/OC3C置位
// 11 升序计数匹配时将OC3A/OC3B/OC3C置位,降序计数匹配时将OC3A/OC3B/OC3C清零
//
// 模式 WGM3x 工作模式说明 TOP OCR1x更新时刻 TOVn置位时刻
// 0 0000 普通模式 0xFFFF 立即 MAX
// 1 0001 8位相位修正PWM 0x00FF TOP BOTTOM
// 2 0010 9位相位修正PWM 0x01FF TOP BOTTOM
// 3 0011 10位相位修正PWM 0x03FF TOP BOTTOM
// 4 0100 CTC OCRnA 立即 MAX
// 5 0101 8位快速PWM 0x00FF TOP TOP
// 6 0110 9位快速PWM 0x01FF TOP TOP
// 7 0111 10位快速PWM 0x03FF TOP TOP
// 8 1000 相位频率修正PWM ICRn BOTTOM BOTTOM
// 9 1001 相位频率修正PWM OCRnA BOTTOM BOTTOM
// 10 1010 相位修正PWM ICRn TOP BOTTOM
// 11 1011 相位修正PWM OCRnA TOP BOTTOM
// 12 1100 CTC ICRn 立即 MAX
// 13 1101 保留 – – –
// 14 1110 快速PWM ICRn TOP TOP
// 15 1111 快速PWM OCRnA TOP TOP
// ICNC3:使能/禁止输入捕捉噪声抑制器
// ICES3:输入捕获触发沿选择,0为下降沿触发,1为上升沿触发
// CS32,CS31,CS30:T/C0时钟预分频选择
// 000:无时钟,T/C不工作 001:1/1
// 010:1/8 011:1/64 100:1/256
// 101:1/1024 110:外部T1脚下降沿驱动 111:外部T1脚上升沿驱动
// FOC3A,FOC3B,FOC3C:强制输出比较通道A,B,C
TCCR3A = TCCR3B = TCCR3C = 0;
//TCNT3H,TCNT3L 定时/计数器3
//OCR3AH,OCR3AL 输出比较寄存器3A
//OCR3BH,OCR3BL 输出比较寄存器3B
//OCR3CH,OCR3CL 输出比较寄存器3C
//ICR3H,ICR3L 输入捕捉寄存器3
}
void init_uart(void)
{
//UDRn USART I/O数据寄存器, 不可用读修改写命令操作, 否则会改变FIFO状态
//UCSRnA USART控制和状态寄存器A
// —————————————————————–
// | RXCn | TXCn | UDREn | FEn | DORn | UPEn | U2Xn | MPCMn |
// —————————————————————–
// RXCn:USART接收结束标志
// TXCn:USART发送结束标志,写1可清除
// UDREn:USART数据寄存器为空标志,只有该标志为1才数据才可写入UDR0
// FEn:帧错误,未正确收到停止位
// DORn:数据过速
// UPEn:奇偶效验错误
// U2Xn:倍速发送,仅对异步操作有影响
// MPCMn:多处理器通讯模式
//UCSRnB USART控制和状态寄存器B
// —————————————————————–
// | RXCIEn| TXCIEn| UDRIEn| RXENn | TXENn | UCSZn2| RXB8n | TXB8n |
// —————————————————————–
// RXCIEn:接收结束中断使能
// TXCIEn:发送结束中断使能
// UDRIEn:USART数据寄存器空中使能
// RXENn:接收使能
// TXENn:发送使能
// UCSZn2:字符长度,具体见下面
// RXB8n:接收数据位8
// TXB8n:发送数据位8
//UCSRxC USART控制和状态寄存器C
// —————————————————————–
// | – | UMSELn| UPMn1 | UPMn0 | USBSn | UCSZn1| UCXZn0| UCPOLn|
// —————————————————————–
// UMSELn:模式选择,0为异步操作,1为同步操作
// UPMn1,UPMn0:奇偶效验模式,00禁止,01保留,10偶效验,11奇校验
// USBSn:停止位选择,0为1位停止位,1为2位停止位
// UCSZn2,UCSZn0:字符长度,000为5位, 001为 6位,010为7位, 011为8位
// 100为保留,101为保留,110为保留,111为9位
// UCPOLn:时钟极性,(异步模式应清零)
// UCPOL0 发送数据位置 接收数据位置
// 0 XCK0上升沿 XCK0下降沿
// 1 XCK0下降沿 XCK0上升沿
//UBRRnL和UBRRnH USART波特率寄存器, UBRRnH15:12为保留位:
// —————————————————————–
// | – | – | – | – | BIT11 | BIT10 | BIT09 | BIT08 |
// —————————————————————–
// —————————————————————–
// | BIT07 | BIT06 | BIT05 | BIT04 | BIT03 | BIT02 | BIT01 | BIT00 |
// —————————————————————–
}
void init_spi(void)
{
//SPCR SPI控制寄存器
// —————————————————————–
// | SPIE | SPE | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 |
// —————————————————————–
// SPIE:SPI中断使能
// SPE:SPI使能
// DORD:数据次序,为1时LSB先发送
// MSTR:是否主机模式,若为主机模式,SS引脚配置为输入,但被拉低则MSTR被清零
// SPSR的SPIF位置位。用户必须重新设置MSTR位进入主机模式。
// CPOL:时钟极性,为1时表示空闲时SCK为高电平,否则为低电平。
// CPHA:时钟相位,为0时为时钟的起始沿采样数据,否则为终止沿采样数据
// SPR1,SPR0:SPI时钟速率选择:00 1/4, 01 1/16, 10 1/64, 11 1/128
//SPSR SPI状态寄存器
// —————————————————————–
// | SPIF | WCOL | – | – | – | – | – | SPI2X |
// —————————————————————–
// SPIF:SPI中断标志,串行发送结束后此位置位,对于查询方式,可先读SPSR,紧着
// 访问SPDR来对SPIF位清零。
// WCOL:写冲突标志,可通过先读SPSR,紧接着访问SPDR来清零。
// SPI2X:SPI倍速,若为主机,SCK最高频率可达CPU频率一半,从机则只能保证为1/4
//SPDR SPI数据寄存器
// —————————————————————–
// | MSB | | | | | | | LSB |
// —————————————————————–
// SPDR为可读写寄存器,写则将启动数据传输,读则读取接收缓冲器
}
void init_twi(void)
{
//TWBR TWI比特率寄存器
// —————————————————————–
// | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
// —————————————————————–
// SCL频率 = CUP时钟频率/(16 + 2 * TWBR * 4 ^ TWPS)
// TWBR值应该不小于10, TWPS为预分频值
//TWCR TWI控制寄存器
// —————————————————————–
// | TWINT | TWEA | TWSTA | TWSTO | TWWC | TWEN | – | TWIE |
// —————————————————————–
// TWINT:TWI中断标志,TWINT标志必须由软件写1清除, 即使在中断服务程序中硬件也不会自动清除
// 在清除TWI标志前一定要首先完成对TWAR TWSR TWDR的访问, 此位清零后TWI立即开始工作。
// TWEA:使能TWI应答,此位控制应答脉冲的产生。
// TWSTA:START状态位,自己想成为主机时置此位,发送START后软件必须清零TWSTA。
// TWSTO:STOP状态位。主模式下,置此位将在总线上产生STOP状态,后TWSTO自动清零;从机模式下
// 置此位可使接口从错误状态恢复到未被寻址的状态,此时总线上不会产生STOP状态。
// TWWC:TWI写冲突标志。每次写TWDR时都将更新此标志。
// TWEN:TWI使能位。置1时TWI引脚将从IO引脚切换到SCL和SDA引脚。
// TWIE:TWI中断使能。
//TWSR TWI状态寄存器
// —————————————————————–
// | TWS7 | TWS6 | TWS5 | TWS4 | TWS3 | – | TWPS1 | TWPS0 |
// —————————————————————–
// TWS7~TWS3:TWI状态
// TWPS1~TWPS0:TWI预分频值。00:1; 01:1/4; 10:1/16; 11:1/64。
//TWDR TWI数据寄存器
// —————————————————————–
// | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
// —————————————————————–
// 发送模式,TWDR中包含了要发送的字节,接收模式TWDR包含了接收到的数据。
// 只要TWINT置位,TWDR的数据就是稳定的。
//TWAR TWI从机地址寄存器
// —————————————————————–
// | TWA6 | TWA5 | TWA4 | TWA3 | TWA2 | TWA1 | TWA0 | TWGCE |
// —————————————————————–
// TWA6~TWA0:TWI从机地址寄存器
// TWGCE:使能TWI广播识别
}
//GICR 通用中断控制寄存器
// —————————————————————–
// | INT1 | INT0 | INT2 | – | – | – | IVSEL | IVCE |
// —————————————————————–
// INT1:使能外部中断1请求
// INT0:使能外部中断0请求
// INT2:使能外部中断2请求
// IVSEL:中断向量选择,为0时中断向量位于FLASH起始地址,为1时位于BOOT区起始地址
// IVCE:中断向量修改使能。改变IVSEL时IVCE必须置位。
//MCUCR MCU控制寄存器
// —————————————————————–
// | SM2 | SE | SM1 | SM0 | ISC11 | ISC10 | ISC01 | ISC00 |
// —————————————————————–
// SM2, SM1, SM0:000:空闲模式
// 001:ADC噪声抑制模式
// 010:掉电模式
// 011:省电模式
// 100:保留
// 101:保留
// 110:Standby模式
// 111:扩展Standby模式
//SE:休眠使能
//ISC11, ISC10: 00:INT1为低电平时产生中断请求
// 01:INT1引脚上任意的逻辑电平变化都将引发中断
// 10:INT1的下降沿产生异步中断请求
// 11:INT1的上升沿产生异步中断请求
//ISC01, ISC00: 00:INT0为低电平时产生中断请求
// 01:INT0引脚上任意的逻辑电平变化都将引发中断
// 10:INT0的下降沿产生异步中断请求
// 11:INT0的上升沿产生异步中断请求
//MCUCSR MCU控制和状态寄存器
// —————————————————————–
// | JTD | – | – | JTRF | WDRF | BORF | FXTRF | PORF |
// —————————————————————–
// JTD:
// JTRF:JTAG复位标志
// WDRF:看门狗复位标志
// BORF:掉电检测复位标志
// EXTRF:外部复位标志
// PORF:上电复位标志
//WDTCR 看门狗定时器控制寄存器
// —————————————————————–
// | – | – | – | WDCE | WDE | WDP2 | WDP1 | WDP0 |
// —————————————————————–
// WDCE:看门狗修改使能,清零WDE位时必须先置位WDCE位,否则不能禁止看门狗
// WDE:看门狗使能,只有WDCE为1时WDE才能清零
// WDP2~WDP0:看门狗定时器预分频值 WDT振荡周期 VCC=3V时溢出时间 VCC=5V时溢出时间
// 000: 16K 14.8ms 14.0ms
// 001: 32K 29.6ms 28.1ms
// 010: 64K 59.1ms 56.2ms
// 011: 128K 0.12s 0.11s
// 100: 256K 0.24s 0.22s
// 101: 512K 0.47s 0.45s
// 110: 1024K 0.95s 0.9s
// 111: 2048K 1.9s 1.8s
//EEARH/EEARL EEPROM地址寄存器
//EEARH
// —————————————————————–
// | – | – | – | – | EEAR11| EEAR10| EEAR9 | EEAR8 |
// —————————————————————–
//EEARL
// —————————————————————–
// | EEAR7 | EEAR6 | EEAR5 | EEAR4 | EEAR3 | EEAR2 | EEAR1 | EEAR0 |
// —————————————————————–
//EEPROM地址,在访问EEPROM前必须为其赋予正确的数据
//EEDR EEPROM数据寄存器
// —————————————————————–
// | MSB | … | … | … | … | … | … | LSB |
// —————————————————————–
//EECR EEPROM控制寄存器
// —————————————————————–
// | – | – | – | – | EERIE | EEMWE | EEWE | EERE |
// —————————————————————–
//EERIE:EEPROM就绪中断使能
//EEMWE:EEPROM主机写使能,当此位为1时,在4个时钟内EEWE置位,数据将写入EEPROM
// EEMWE置位4个时钟后硬件将其清零
//EEWE:EEPROM写使能
//EERE:EEPROM读使能。当EEPROM地址设置好后,需置位EERE以便将数据读入EEAR
//EEPROM写时序:
//a等待EEWE位为0
//b等待SPMCSR的SPMEN位为0,此步只在软件包含引导程序,且允许CPU对Flash编程时才有用
//c将新的EEPROM地址写入EEAR
//d将新的EEPROM数据写入EEDR
//e对EECR的EEMWE位写1,同时清零EEWE位
//f在置位EEMWE位的4个周期内置位EEWE位
——————————————————————————————————
七、AVR移位算法详细解释(1<<X)
很多初学者都会被移位算法迷惑,移位算法形如(1<<X)这样的形式,高手写程序时,习惯用移位算法来写出各个寄存器的使用。比如下面一段是AVR 的USART 的初始化代码。
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSR0B = (1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN); // RXCIE=1;TXCIE=1;UDREIE=0;RXEN=1;TXEN=1
这样的写法对高手是福,这些代码里面说明了操作了寄存器的哪些位,能够看出它的操作的意义;对新手确是祸害,因为新手看不懂这样的程序。
回到开始的地方,解释一下,什么是移位算法:
如:A = (1<<2),1写成二进制就是0000 0001,这个一左移2位就是0000 0100,所以得到的数A为0000 0100,即0x04。
再如:B = (2<<4),2写成二进制就是0000 0010,这个一左移4位就是0010 0000,所以得到的数B为0010 0000,即0x20。
上面两个移位算法都是正确的,第一种写法,表示第三位为1其余都是0的数,数的时候是从0数起的,再比如(1<<0)表示的是0000 0001,(1<<7)表示的是1000 0000,但是第二种写法没有没有这种意义,移位也用于乘除法,左移一位乘以2,右移移位除以2,上面的第二种写法2左移四位得到的数是2×2×2×2×2=32,也就是上面的0x20。
我们再来看上面的这句话:UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSRC是一个和串口通讯有关的一个八位寄存器,他的每一位都有特殊的定义,我们通过查数据手册可以看到,如下的内容。
我们在程序中包含的头文件iom16v.h类似的文件会有#define URSEL 7 这样的定义,1<<URSEL即是位7,1<<UCSZ1选择位2,1<<UCSZ0选择位1,整句话UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);的效果就是让UCSRC的位七,位二,位一为高,其他都为低,然后在数据手册里面你可以看到各个位的作用。UCSRC = (1<<7)|(1<<2)|(1<<1) 即UCSRC = 1000 0110。
——————————————————————————————————