AVR单片机_实验4:按键扫描实验

曾巧文 发布于:2012-4-29 17:09 分类:AVR单片机 标签: 实验 单片机 AVR

1 实验目的

通过实验,进一步学习AVR单片机定时中断的用法,理解并掌握按键扫描的状态机设计方法。

2 实验内容

1、在单片机实验板上有两个独立按键分别接在单片机PD3和PA7.注PD3引脚无外部上拉电阻,需要打开内部上拉电阻,采用状态机设计方法设计按键扫描程序

2、实现PD3上的按键单击时,数码管显示内容加一,PA7上的按键单击时,数码管显示内容减一;

3 实验预习要求:

仔细阅读ATmega16单片机的数据手册,了解定时计数器相关寄存器的设置;

  1. 实验步骤

1、启动ICCAVR,新建工程文件"Timer.PRJ",新建Timer.c文件,并将文件Timer.c添加到Timer.PRJ工程中,并设置project->option->target 下的device configuration 选择ATMega16;

2、利用Application Builder产生Timer0初始化代码;系统时钟选择4MHZ,设置为2ms中断一次,建议使用CTC模式产生定时中断;

  1. 在Timer.c文件下添加相应代码,在定时中断服务程序中实现数码管的定时刷新(动态扫描显示),并且在定时中断中实现10ms的时标用于按键扫描;
  2. 在主程序中以10ms为间隔定时扫描按键,采用状态机的设计方法
  3. 根据按键值的不同对数码管显示的内容做相应改变(在主程序中实现);
  4. 选择【Project】->【Rebuild All】编译工程,通过PROGISP程序下载程序到单片机,观察实验现象。

(1)数码管相关电路(所用的IO包括PD7-4,PB0,PB1,PA0)

(2)按键电路,无外部上拉电阻,接于单片机的PD3(需使能内部上拉电阻)

(3)按键电路,有外部上拉电阻,接于单片机的PA7

实验四 按键扫描实验


1 实验目的

通过实验,进一步学习AVR单片机中定时中断的用法,理解并掌握按键扫描的状态机设计方法。

2 实验内容

1、在单片机实验板上有两个独立按键分别接在单片机PD3(SW8)和PA7(KEY1).注PD3引脚无外部上拉电阻,需要打开内部上拉电阻,采用状态机设计方法设计按键扫描程序

2、实现PD3上的按键单击时,数码管显示内容加一,PA7上的按键单击时,数码管显示内容减一;

3 在定时中断中实现四位数码管的显示,并且设计10ms的时标用于按键的定时扫描,写出中断服务程序和定时器初始化代码;

//TIMER0 initialize - prescale:256
// WGM: CTC
// desired value: 1KHz
// actual value:  0.977KHz (-2.4%)
void timer0_init(void)
{
 TCCR0 = 0x00; //stop
 TCNT0 = 0xFD; //set count
 OCR0  = 0x03;  //set compare
 TCCR0 = 0x0C; //start timer
}
unsigned char i = 4, j = 0,time_10ms_ok=0;
unsigned int buff=4567;
#pragma interrupt_handler timer0_comp_isr:iv_TIM0_COMP
void timer0_comp_isr(void)
{
 //compare occured TCNT0=OCR0
 PORTD |= 0XF0;
 HC595_send_byte(led_7[Disp_data[i-4]]);
 PORTD &= ~(1 << i);
 if(++i>7){i = 4;}
 if(++j >= 10)
 {
   j=0;
   time_10ms_ok=1;
 }
}

4 设计按键扫描程序识别SW8和KEY1这两个按键。

提示:函数原型 char read_key(void),该函数没有参数,有char类型的返回值,返回值不同代表所按键不同,例如当单击SW8时返回值为1,当单击KEY1是返回值为2。

 

unsigned char read_key()
{
  unsigned char key_return = 0;
  static unsigned char key_state = 0;
  switch(key_state)
  {
    case 0:
	  if(!(PIND & (1<<3)) || !(PINA &(1<<7)))
	    key_state = 1;
	  break;
	case 1:
	  if(!(PIND & (1<<3)) || !(PINA &(1<<7)))
	  {
	    key_state = 2;
		if(!(PIND & (1<<3)))key_return = 1;
		else if(!(PINA &(1<<7)))key_return = 2;
	  }
	  else
	    key_state = 0;
	  break;
	case 2:
	  if((PIND & (1<<3)) && (PINA &(1<<7)))key_state = 0;
	break;
  }
  return key_return;
}

 

5、在主程序中定时扫描按键,实现如下功能:单击SW8,显示内容加一,单击KEY1,显示内容减一;(注:只写出实现过程,按键扫描程序和显示程序直接调用前面的内容即可,无需写在此处)

  

//ICC-AVR application builder : 2012-4-9 6:39:28
// Target : M16
// Crystal: 1.0000Mhz

#include <iom16v.h>
#include <macros.h>

void port_init(void)
{
 PORTA = 0x00;
 DDRA  = 0x01;
 PORTB = 0x00;
 DDRB  = 0x03;
 PORTC = 0x00; //m103 output only
 DDRC  = 0x00;
 PORTD = 0x08;
 DDRD  = 0xF0;
}

//TIMER0 initialize - prescale:256
// WGM: CTC
// desired value: 1KHz
// actual value:  0.977KHz (-2.4%)
void timer0_init(void)
{
 TCCR0 = 0x00; //stop
 TCNT0 = 0xFD; //set count
 OCR0  = 0x03;  //set compare
 TCCR0 = 0x0C; //start timer
}
//定义字符表 		   														
unsigned char led_7[14]={0xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
		 	  			 0x80,0x90,0xff,0x7f,0xc6,0x00};
						 
unsigned char Disp_data[4]={0x00,0x00,0x00,0x00};
						 
#define CLR_SHCLK()  		PORTB&=~(1<<1)		  //移位时钟 SCLK
#define SET_SHCLK()  		PORTB|=(1<<1)		  //移位时钟 SCLK,上升沿

#define CLR_STCLK()  		PORTB&=~(1<<0)		  //锁存时钟 RCLK
#define SET_STCLK()  		PORTB|=(1<<0)		  //拉高锁存时钟,上升沿

#define CLR_DS()			PORTA&=~(1<<0)		  //清零
#define SET_DS()			PORTA|=(1<<0)		  //置位

void HC595_send_byte(unsigned char SndData)
{
    char i;
    for(i=0;i<8;i++)
    {  
        if(SndData&(1<<(7-i)))
        {
            SET_DS();  //数据引脚输出1 
        }
        else
        {
            CLR_DS();  //数据引脚输出0
        }
		CLR_SHCLK();		  //移位时钟 SHCLK 输出0 
        SET_SHCLK();		  //移位时钟 SHCLK输出0, 先输出0再输出1,产生一个上升沿
    }
	CLR_STCLK();			  //锁存时钟 STCLK 输出0 
	SET_STCLK();			  //锁存时钟 STCLK 输出1 ,先输出0再输出1,产生一个上升沿
}

unsigned char i = 4, j = 0,time_10ms_ok=0;
unsigned int buff=4567;
#pragma interrupt_handler timer0_comp_isr:iv_TIM0_COMP
void timer0_comp_isr(void)
{
 //compare occured TCNT0=OCR0
 PORTD |= 0XF0;
 HC595_send_byte(led_7[Disp_data[i-4]]);
 PORTD &= ~(1 << i);
 if(++i>7){i = 4;}
 if(++j >= 10)
 {
   j=0;
   time_10ms_ok=1;
 }
}

#pragma interrupt_handler int1_isr:iv_INT1
void int1_isr(void)
{
 //external interupt on INT1
}

//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 timer0_init();

 MCUCR = 0x08;
 GICR  = 0x80;
 TIMSK = 0x02; //timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}

unsigned char read_key()
{
  unsigned char key_return = 0;
  static unsigned char key_state = 0;
  switch(key_state)
  {
    case 0:
	  if(!(PIND & (1<<3)) || !(PINA &(1<<7)))
	    key_state = 1;
	  break;
	case 1:
	  if(!(PIND & (1<<3)) || !(PINA &(1<<7)))
	  {
	    key_state = 2;
		if(!(PIND & (1<<3)))key_return = 1;
		else if(!(PINA &(1<<7)))key_return = 2;
	  }
	  else
	    key_state = 0;
	  break;
	case 2:
	  if((PIND & (1<<3)) && (PINA &(1<<7)))key_state = 0;
	break;
  }
  return key_return;
}

void main()
{
  char key_flag;
  init_devices();
  while(1)
  {
    Disp_data[0] = buff % 10;
	Disp_data[1] = buff / 10 % 10;
	Disp_data[2] = buff / 100 % 10;
	Disp_data[3] = buff /1000;
    if(time_10ms_ok)
	{
	  key_flag=read_key();
	  time_10ms_ok = 0;
	  if(key_flag == 1)
	  {
	    buff++;
	  }
	  else if(key_flag == 2)
	  {
	    buff--;
	  }
	}
  }
}

版权所有:《曾巧文博客-关注互联网IT技术,记录生活点滴》 => 《AVR单片机_实验4:按键扫描实验
本文地址://qiaowen.net/post-1186.html
除非注明,文章均为 《曾巧文博客-关注互联网IT技术,记录生活点滴》 原创,欢迎转载!转载请注明本文地址,谢谢。

有 5125 人浏览,获得评论 0 条

发表评论:

Powered by emlog 粤ICP备12040901号

>>本作品采用-知识共享署名-非商业-禁止演绎-协议-进行许可 |站点地图 | | | | 开放分类目录 |