内容包括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编译环境设置

1、使用AVR GCC做为编译器
AVR单片机及其开发环境-编程知识网

—————————————

2、选择仿真调试平台 
AVR单片机及其开发环境-编程知识网

—————————————

3、选择Device,设置Frequency,代码优化选项Optimization,输出hex文件 
AVR单片机及其开发环境-编程知识网

—————————————

4、设置包含文件(头文件)路径  AVR单片机及其开发环境-编程知识网

—————————————

5、设置库文件路径 
AVR单片机及其开发环境-编程知识网

—————————————

6、设置工具链路径(不使用AVR Toolchain)  AVR单片机及其开发环境-编程知识网 如此便可使用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单片机及其开发环境-编程知识网

——————————————————————————————————

五、AVR JTAG ICE MKII仿真器

AVR单片机及其开发环境-编程知识网

注意:此处的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是一个和串口通讯有关的一个八位寄存器,他的每一位都有特殊的定义,我们通过查数据手册可以看到,如下的内容。

AVR单片机及其开发环境-编程知识网

我们在程序中包含的头文件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。

——————————————————————————————————