搜索
您的当前位置:首页AVR单片机(1)

AVR单片机(1)

来源:小侦探旅游网
AVR单片机 (ATmega16)

培训宗旨:引导为主 培养编程思维

时间分配(一学期):三分之一时间讲解;

三分之二时间动手实验。

具体时间:星期六晚上6:00~9:00

内容形式:

1、软、硬件知识 (一)讲解 2、实验经验

3、常用程序(思维)分析

1、专业讲座(请资深讲师)

(二)讲座 2、课外讲座(如书记等)

3、电影(专业性强的短片)(李世维讲座)

1、硬件测试与软件使用

(三)实验内容 2、汇编语言编程

3、AVR单片机内部资源的使用

建议方法:先由指导老师讲解实验内容的原理、特点、应用、实践应用中的经验

以及编程思维的分析,再由会员自己理解、自己验证、运用原理设计应用、调试程序。在会员动手的过程中,由摇篮的部长(三名)从旁指导。

1

实验一 软件和硬件的认识

一、

实验目的:

1、掌握硬件原理。

2、初步掌握实验板的使用方法。 3、熟悉软件工作界面。 二、

实验仪器: ATmage16实验板 一块

PC机 一台

三、 实验内容及步骤:

1、插上电源,按下开关。观察批示灯是否点亮。

电源(可输入7~12V)

ATmega16管脚图

2

2、由原理可知I/O口的批示灯为低电平亮,在实验板上取地与I/O口相接,观察是否点亮。

I/O口LED显示与接口

3、打开编程界面,点击各栏,认识各栏的用途。

AVRICC IDE 软件的工作界面

4、输入以下程序: #include int main(void) {

DDRA = 0xff; /* all outputs */ DDRB = 0xff; /* all outputs */ DDRC = 0xff; /*all outputs */ DDRD = 0xff; /*all outputs */

3

PORTA = 0x00; /* 输出低电平 */ PORTB = 0x00; /* 输出低电平 */ PORTC = 0x00; /* 输出低电平 */ PORTD = 0x00; /* 输出低电平 */ while(1); }

观察I/O口的灯是否被点亮。

实验二 I/O口的输入与输出

一、 实验目的:

1、了解IO口的结构; 2、熟悉IO口的特性; 3、掌握IO口的控制。

二、实验仪器:ATmage16实验板 一块

PC机 一台

三、 实验原理:

作为通用数字I/O 使用时,AVR 所有的I/O 端口都具有真正的读- 修改- 写功能。这意味着用SBI 或CBI 指令改变某些管脚的方向( 或者是端口电平、禁止/ 使能上拉电阻) 时不会改变其他管脚的方向( 或者是端口电平、禁止/ 使能上拉电阻)。输出缓冲器具有对称的驱动能力,可以输出或吸收大电流,直接驱动LED。所有的端口引脚都具有与电压无关的上拉电阻。并有保护二极管与VCC 和地相连,如 Figure23 所示。在控制I/O时,分别由方向寄存器DDRX与数据寄存器PORTX控制I/O的状态,如下表。

Figure 23. I/O 引脚等效原理图

4

I/O口LED显示与接口

四、 实验内容及步骤:

输入以下程序:这个程序为流水灯

#include

//*******************延时 us void delay_us(int t) {

do t--;

while(t>1); }

//*******************延时 ms void delay_ms(unsigned int t) {

5

while(t!=0) {

delay_us(1142); t--;} }

int main(void) {

DDRA = 0xff; /* all outputs */ DDRB = 0xff; /* all outputs */ DDRC = 0xff; /*all outputs */ DDRD = 0xff; /*all outputs */ PORTA=0XFF; PORTB=0XFF; PORTC=0XFF; PORTD=0XFF; while(1)

{//***IO口输出低电平有效,如:0X01为十六进制数,二进制表示为00000001B,再取反

PORTA=~0X01;

delay_ms(1000);//************延时1秒 PORTA=~0X02; delay_ms(1000); PORTA=~0X04; delay_ms(1000); PORTA=~0X08; delay_ms(1000); PORTA=~0X10; delay_ms(1000); PORTA=~0X20; delay_ms(1000); PORTA=~0X40; delay_ms(1000); PORTA=~0X80; delay_ms(1000);

PORTA=0XFF;

PORTB=~0X01;

delay_ms(1000);//************延时1秒 PORTB=~0X02; delay_ms(1000); PORTB=~0X04; delay_ms(1000); PORTB=~0X08; delay_ms(1000);

6

PORTB=~0X10; delay_ms(1000); PORTB=~0X20; delay_ms(1000); PORTB=~0X40; delay_ms(1000); PORTB=~0X80; delay_ms(1000);

PORTB=0XFF; PORTC=~0X01; delay_ms(1000); PORTC=~0X02; delay_ms(1000); PORTC=~0X04; delay_ms(1000); PORTC=~0X08; delay_ms(1000); PORTC=~0X10; delay_ms(1000); PORTC=~0X20;

delay_ms(1000); PORTC=~0X40; delay_ms(1000); PORTC=~0X80; delay_ms(1000);

PORTC=0XFF; PORTD=~0X01; delay_ms(1000); PORTD=~0X02; delay_ms(1000); PORTD=~0X04; delay_ms(1000); PORTD=~0X08; delay_ms(1000); PORTD=~0X10; delay_ms(1000); PORTD=~0X20; delay_ms(1000); PORTD=~0X40; delay_ms(1000); PORTD=~0X80; delay_ms(1000); PORTD=0XFF;

7

} }

观看现象是不是流水灯。

实验三 外部中断

一、 实验目的:

1、了解外部中断的库函数;

2、熟悉外部中断的特性;

3、掌握外部中断的使用。

二、实验仪器:ATmage16实验板 一块

PC机 一台

三、实验原理:

外部中断通过引脚INT0 与INT1 或PCINT23..0 触发。只要使能了中断,即使引脚INT0与INT1 或PCINT23..0 配置为输出,只要电平发生了合适的变化,中断也会触发。这个特点可以用来产生软件中断。 只要使能, PCINT23..16 引脚上的电平变化将触发外部中断PCI2, PCINT14..8 引脚上的电平变化将触发外部中断PCI1, PCINT7..0 将触发外部中断PCI0。PCMSK2、PCMSK1 与PCMSK0 寄存器则用来检测是哪个引脚上的电平发生了变化。PCINT23..0 外部中断的检测是异步的。也就是说,和其他中断方式一样,这些中断也可以用来将器件从休眠模式唤醒。INT0 与INT1 中断可以由下降沿、上升沿,或者是低电平触发。具体由外部中断控制寄存器A – EICRA 的设置来确定。当INT0 或INT1 中断使能且设定为电平触发时,只要引脚电平被拉低,中断就会产生。若要求INT0 或INT1 在信号下降沿或上升沿触发中断,则I/O时钟必须工作(请参见P23”时钟系统及其分布” 了解更多信息)。INT0与INT1 的低电平中断检测是异步的。也就是说它可以用来将器件从休眠模式唤醒。在休眠过程( 除了空闲 模式) 中I/O 时钟是停止的。通过电平中断将MCU 从掉电模式唤醒时,要保证低电平保持一定的时间以使MCU 完成唤醒过程并触发中断。如果触发电平在启动时间结束前就消失, MCU 将被唤醒,但中断不会被触发。启动时间由熔丝位SUT 与CKSEL 决定。详见 P23” 系统时钟及其选项” 。

外部中断控制寄存器MCUCR 外部中断控制寄存器 A 包括决定中断触发方式的控制位。

8

位1, 0 – ISC01, ISC00: 中断触发方式控制0 之位1 与位0外部中断0 由引脚INT0 激发,如果SREG 寄存器的I 标志位和相应的中断屏蔽位置位的话。触发方式如Table35 所示。在检测边沿前MCU 首先采样INT0 引脚上的电平。如果选择了边沿触发方式或电平变化触发方式,那么持续时间大于一个时钟周期的脉冲将触发中断,过短的脉冲则不能保证触发中断。如果选择低电平触发方式,那么低电平必须保持到当前指令执行完成。中断完成后回到被中断的位置。

外部中断控制寄存器MCUCR 外部中断控制寄存器 A 包括决定中断触发方式的控制位。

通用中断控制寄存器 GICR,控制外部中断使能位,具体如下:

9

四 ICC软件中断程序书写格式及16中断向量表

16中断向量表 五 实验步骤及内容:

输入程序:本程序一开始是IO口中的A口以流水灯工作,一旦有外部中断请求,就是B口以流水灯工作,循环一次后回到被中断处继续运行。

程序如下:

#include #include

//*******************延时 us

10

void delay_us(int t) { do t--;

while(t>1); }

//*******************延时 ms void delay_ms(unsigned int t) {

while(t!=0) {

delay_us(1142); t--;} }

#pragma interrupt_handler INT_0:2 void INT_0 (void) {

PORTC=0XFF; PORTB=~0X01; delay_ms(1000); PORTB=~0X02; delay_ms(1000); PORTB=~0X04; delay_ms(1000); PORTB=~0X08; delay_ms(1000); PORTB=~0X10; delay_ms(1000); PORTB=~0X20; delay_ms(1000); PORTB=~0X40; delay_ms(1000); PORTB=~0X80; delay_ms(1000); PORTB=0XFF; }

void main(void) {

DDRA = 0xff; /*输出 */ DDRB = 0xff; /*输出 */ DDRC = 0xff; /*输出*/ DDRD = 0xff; /*输出*/ PORTA=0XFF; PORTB=0XFF;

//外部中断0执行函数11

PORTC=0XFF; PORTD=0XFF;

MCUCR=0X02; //定义外部中断INT0为下降沿产生中断请求 GICR=0X40; //中断屏蔽寄存器开INT0 SEI(); //******开全局中断 for (;;) {

PORTA=~0X01; delay_ms(1000); PORTA=~0X02; delay_ms(1000); PORTA=~0X04; delay_ms(1000); PORTA=~0X08; delay_ms(1000); PORTA=~0X10; delay_ms(1000); PORTA=~0X20; delay_ms(1000); PORTA=~0X40; delay_ms(1000);

PORTA=~0X80; delay_ms(1000); } }

实验四 数码LED 实验

一、

实验目的:

1、了解数码管的原理; 2、熟悉数码管的使用;

3、掌握外部中断和数码管动态显示的应用。 二 、 实验仪器:ATmage16实验板 一块

PC机 一台

三、 实验原理:数码管原理图如下:

12

多个数码管的动态显示是利用人的眼睛在瞬间无法识别的原理来实现在,如电灯也是利用这个原理。

四、 实验步骤及内容:这个程序是数码管动态显示,按INT0键加1,一直到

数码管显示为9999再重新计数。

实验程序如下:

#include

#include

int led[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //*******显示符0,1,2,3,4,5,6,7,8,9, unsigned int i; int g,s,b,q;

//*******************延时 us void delay_us(int t) { do t--; while(t>1); }

//*******************延时 ms void delay_ms(unsigned int t) {

while(t!=0) {

delay_us(1142); t--;} }

#pragma interrupt_handler INT_0:2 //外部中断0执行函数 void INT_0 (void) { i++;

delay_ms(15);//******键盘防抖动 }

void main(void)

13

{

DDRD = 0xff; /* all outputs */ DDRC = 0xff; /* all outputs */ DDRB = 0xff; /*all outputs */ PORTB=0XFF; PORTC=0X00; PORTD=0XFF;

MCUCR=0X02; //定义外部中断INT0为下降沿产生中断请求 GICR=0X40; //中断屏蔽寄存器开INT0 SEI(); //******开全局中断

for (;;)//****显示按键次数 {

if(i>9999) i=0;

g=i%10; //取个位,取余 PORTC=0X01; PORTB=led[g]; delay_ms(1);

s=i%100/10; //取十位 PORTC=0X02; PORTB=led[s]; delay_ms(1);

b=i%1000/100; //取百位 PORTC=0X04; PORTB=led[b]; delay_ms(1);

q=i%10000/1000; // 取千位 PORTC=0X08; PORTB=led[q]; delay_ms(1); /* for (i=0;i<4;i++) {

g=i%10; //取余 PORTC=|(1<g=i/10; //取整 PORTC=0x00;; )*/ } }

14

实验五 键盘接口实验

一、 实验目的:1、了解IO口的结构; 2、熟悉键盘的程序原理; 3、掌握键盘的使用。 二、实验仪器: MEGA16实验板 一块

PC机 一台

三、

实验原理:在AVR 单片机中,当I/O方向设置为输入,电平被设置为

高电平时,一旦外部接入低电平,端口电平被拉低,电平变化会反映相应端口PINX寄存器中,利用这一特点,在键盘中采用设置行所对IO口为输出,高电平,列所对IO口为输入,高电平。对行所对IO口电平逐个设置为低电平,此时列线上某列电平被拉低。通过读取列线上电平,计算出所按键值。

J60112SW-PB4SW-PB8SW-PBCSW-PB21SW-PB5SW-PB9SW-PBDSW-PB2SW-PB6SW-PBASW-PBESW-PB3SW-PB7SW-PBBSW-PBFSW-PB330RJ1RJ2330RJ3330RJ43300123456712345678KEY 四 实验程序

#include #include

/////////////////////////////延时/////////////////////////////////////////// void delay_us( int t) //us { do t--;

while(t>1); }

void delay_ms(unsigned int t) //ms {

while(t!=0) {

delay_us(1142);

15

t--; } }

unsigned char led[]={ 0X3F,/*0*/ //七段译码表

0X06,/*1*/

0X5B,/*2*/ 0X4F,/*3*/ 0X66,/*4*/ 0X6D,/*5*/ 0X7D,/*6*/ 0X07,/*7*/ 0X7F,/*8*/ 0X6F,/*9*/ 0X77,/*A*/ 0X7C,/*b*/ 0X39,/*C*/ 0X5E,/*d*/ 0X79,/*E*/ 0X71,/*F*/

}; //显示符0,1,2,3,4,5,6,7,8,9,

unsigned char led_buff[]={0x3f,0x3f,0x3f,0x3f,0x3f,0x3f}; //显示缓冲区

unsigned char scan_key(void) //不做按键释放检查的键盘扫描函数{

unsigned char i,temp;

DDRD=0X0F; //设置D口的高四位为输入,低四位为输出 PORTD=0XFf; //D口输出高电平 for(i=0;i<4;i++) {

PORTD=~(1<temp=PIND&0XF0; //temp取D口高四位的值 if(temp!=0xf0) //如有键按下,延时15ms {

delay_ms(15); //延时用来消除显示抖动 temp=PIND&0xf0; //再读键盘 if(temp!=0xf0) {

temp&=0xf0;

switch (temp) //计算键值 {

case 0x70:temp=15-(3-i)*4;break; case 0xb0:temp=14-(3-i)*4;break; case 0xd0:temp=13-(3-i)*4;break; case 0xe0:temp=12-(3-i)*4;break;

16

default:temp=0x7f; }

return temp; //返回temp } }

PORTD=0xff; }

return 0x7f; }

void port_init(void) {

DDRA=0xff; PORTA=0xff; DDRC=0xff; PORTC=0Xff; DDRD=0x0f; PORTD=0xff; }

void display(void) {

unsigned int i=0; for(;i<6;i++) {

PORTA=led_buff[i]; PORTC=(1<void main(void) {

unsigned char key1,key2; unsigned char i; port_init(); for(;;) {

key1=scan_key(); if (key1!=0x7f) { do { key2=scan_key(); display(); }

//初始化IO //六位数码管显示 //PA口为段选 //PC口为位选 //键盘扫描17

while(key1==key2);

for (i=0;i<5;i++) //显示 led_buff[5-i]=led_buff[4-i]; //按下一次移一次 led_buff[0]=led[key1]; //做led显示转换 }

display(); //显示 } }

实验六 模数转换AD 实验

一、 实验目的:

1、了解IO口的结构; 2、熟悉A/D的特性; 3、掌握A/D的使用。

二、实验仪器:MEGA16实验板 一块

PC机 一台

三、 实验原理: 四、 实验步骤及内容:

#include #include #define VREF 4.950 unsigned int V=0; float Vin=0;

unsigned char led[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F}; //0-9 unsigned char led_putff[]={0X3F,0X3F,0X3F,0X3F};

//*******************延时 us void delay_us(int t) { do

t--; while(t>1); }

//*******************延时 ms void delay_ms(unsigned int t) {

18

while(t!=0) {

delay_us(1142); t--;} }

/*....中断....*/

#pragma interrupt_handler ADC_isr:15 void ADC_isr(void) {

V=ADCL;

V=(ADCH<<8)+V; //读取转换数值 }

/*....系统初始化....*/ Void chushihua(void) {

DDRD=0XFF; //位选 DDRB=0XFF; //数码管

DDRA=0XFE; //C0口电压输入 PORTD=0X00; PORTB=0XC0; PORTA=0X00;

ADCSRA|=(1</*....AD初始化....*/ void ad_link(void) {

ADCSRA|=(1<ADCSRA|=(1<ADMUX=0X40; //右对齐,基准电源VREF。零通道SFIOR=0X00; //开启连续模式 }

/*....计算转换值....*/ void led_put(void) {

unsigned char sreg; unsigned char i=0; unsigned char f=0;

19

unsigned int X=0;

sreg = SREG; //保存全局中断标志 CLI(); //禁用中断 Vin=V*VREF/1024; //转换数值 X=(unsigned short)(1000*Vin); for(i=0;i<4;i++) {

f=X%10;

led_putff[i]=led[f];

X=X/10; }

led_putff[3]=0X80|led_putff[3];

SREG=sreg; //恢复全局中断标志 }

/*....数码管扫描....*/ void display(void) {

unsigned char i=0; for(i=0;i<4;i++) {

PORTB=led_putff[i]; PORTD|=(1</*....主函数....*/

void main(void) {

chushihua(); ad_link(); for(;;) {

led_put(); display(); } }

实验七 PWM使用

一、 实验目的:

20

1、熟悉PWM的原理与特性; 2、掌握PWM的使用。

二、实验仪器: MEGA16实验板 一块 PC机 一台

三 实验目的:输出频率固定,占空比可调的方波,分别由按键控制占空比的增加,每次增减量为0.1。 四 、实验原理:

利用MEGA16芯片内部8位定时器的快速工作模式产生可调的PWM,快速PWM 模式

(WGM01:0 = 3) 可用来产生高频的PWM 波形。快速PWM 模式与其他PWM模式的不同之处是其单斜坡工作方式。计数器从BOTTOM计到MAX,然后立即回到BOTTOM重新开始。对于普通的比较输出模式,输出比较引脚OC0在TCNT0与OCR0匹配时清零,在BOTTOM 时置位;对于反向比较输出模式, OC0 的动作正好相反。由于使用了单斜坡模式,快速PWM 模式的工作频率比使用双斜坡的相位修正PWM 模式高一倍。此高频操作特性使得快速PWM 模式十分适合于功率调节,整流和DAC 应用。高频可以减小外部元器件( 电感,电容) 的物理尺寸,从而降低系统成本。工作于快速PWM 模式时,计数器的数值一直增加到MAX,然后在后面的一个时钟周期清零。具体的时序图为Figure 32。图中柱状的TCNT0 表示这是单边斜坡操作。方框图同时包含了普通的PWM 输出以及反向PWM 输出。TCNT0 斜坡上的短水平线表示OCR0

和TCNT0 的比较匹配。

Figure 32. 快速PWM 模式时序图、

计时器数值达到MAX 时T/C 溢出标志TOV0 置位。如果中断使能,在中断服务程序可以更新比较值。工作于快速PWM 模式时,比较单元可以在OC0 引脚上输出PWM 波形。设置COM01:0为2 可以产生普通的PWM 信号;为3 则可以产生反向PWM 波形。要想在引脚上得到输出信号还必须将OC0 的数据方向设置为输出。产生PWM 波形的机理是OC0 寄存器在OCR0 与TCNT0 匹配时置位( 或清零),以及在计数器清零( 从MAX变为BOTTOM) 的那一个定时器时钟周期清零( 或置位)。输出的PWM 频率可以通过如下公式计算得到:

21

五 实验程序

#include #include #define BOTTOM 0 unsigned char flag=0; unsigned char X; unsigned char i=0; unsigned char Z=0;

//*******************延时 us void delay_us(int t) { do

t--; while(t>1); }

//*******************延时 ms void delay_ms(unsigned int t) {

while(t!=0) {

delay_us(1142); t--;} }

void time_init(void) {

OCR0=128;

TCNT0=BOTTOM;

TCCR0|=(1<TCCR0|=(1<TIMSK|=(1<#pragma interrupt_handler timer0_ovf_isr:10 void timer0_ovf_isr(void)

22

{

TCNT0=BOTTOM;

}

void per(void) {

if(PIND==0XFB) //加键 {

if(Z<10) Z=Z+1; }

if(PIND==0XF7) //减键 {

if(Z>0) Z=Z-1; } }

void main(void) {

DDRB=0XFF; PORTB=0XFF;

DDRD=0X00;

PORTD=0XFF; //D2 键为脉宽加键.D3 键为脉宽减键,增量为0.1 time_init(); SEI(); for(;;) {

if(PIND!=0XFF)

delay_us(30); if(PIND!=0XFF) per();

X=(unsigned char)((Z*256)/10); OCR0=X; } }

实验八 UART通讯

一、 实验目的:

1、了解电脑与单片机的通讯方式;

2、熟悉USART的原理与特性;

3、学会单片机与单片机之间的串口通讯。

二、实验仪器:MEGA16实验板 一块

23

PC机 一台 RS232线

三 、实验原理:

本程序简单的示范了如何使用ATMEGA16的USART USART的设置 波特率的计算 发送采用查询方式

接收采用中断方式

24

因篇幅问题不能全部显示,请点此查看更多更全内容

Top