//ICC-AVR application builder : 2011/8/9 16:42:16
// Target : M128
// hui.he@qq.com
//本程序能够实现8个独立按键(接在同一组IO口上的),这里只给出了后四个按键的程序和电路
// Crystal: 8.0000Mhz
//开发工具:ICCAVR 7.2
#include <iom128v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
//全局变量,在主程序中检测定时时间是否已到
unsigned char key_stime_ok;
//端口初始化,自动生成的代码
void port_init(void)
{
PORTA = 0xFF;
DDRA = 0xFF;
PORTB = 0xFF;
DDRB = 0xFF;
PORTC = 0xFF; //m103 output only
DDRC = 0xFF;
PORTD = 0xFF;
DDRD = 0xFF;
PORTE = 0xFF;
DDRE = 0xFF;
PORTF = 0xFF;
DDRF = 0xFF;
PORTG = 0xFF;
DDRG = 0xFF;
}
//TIMER0 initialize - prescale:1024
// WGM: CTC 比较方式,定时器0,定时10ms,程序是自动生成的
// desired value: 10mSec 延时10ms
// actual value: 10.112mSec (-1.1%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
ASSR = 0x00; //set async mode
TCNT0 = 0xB2; //set count
OCR0 = 0x4E;
TCCR0 = 0x0F; //start timer
}
//中断服务子程序:定时器0,ctc比较溢出,中断号为16,可查询mega128的手册
#pragma interrupt_handler timer0_compa_isr:16
void timer0_compa_isr(void)
{
//compare occured TCNT1=OCR1A
key_stime_ok = 1;
}
//定义按键宏
#define key_1 0b11111110
#define key_2 0b11111101
#define key_3 0b11111011
#define key_4 0b11110111
#define key_5 0b11101111
#define key_6 0b11011111
#define key_7 0b10111111
#define key_8 0b01111111
#define key_no 0b11111111 //没有按键按下
//定义按键状态机,参考马潮的avr单片机教材第九章
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
//==================================================================
//检测是否有按键按下,返回值是所按按键的值(即前边定义的各键的宏)
//这是状态机检测按键的核心程序
//==================================================================
unsigned char read_key(void)
{
static unsigned char key_state = 0,key_old;
unsigned char key_press,key_return = key_no;
key_press = PIND | 0x0F ; // 读按键I/O电平 0x0F,表示只读取d4,d5,d6,d7引脚的值(根据电路)
switch (key_state)
{
case key_state_0: // 按键初始态
if (key_press != key_no) key_state = key_state_1; // 键被按下,状态转换到键确认态
break;
case key_state_1: // 按键确认态
if (key_press == key_old) // 与原电平比较(消抖处理)
{
key_return = key_press;
key_state = key_state_2; // 状态转换到判键释放态
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态(消抖)
break;
case key_state_2:
if (key_press != key_old)
key_state = key_state_0; //按键已释放(或转按其它键),转换到按键初始态
break;
}
key_old = key_press;
return key_return;
}
//初始化设备
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
XDIV = 0x00; //xtal divider
XMCRA = 0x00; //external memory
port_init();
timer0_init();
MCUCR = 0x00;
EICRA = 0x00; //extended ext ints
EICRB = 0x00; //extended ext ints
EIMSK = 0x00;
TIMSK = 0x02; //timer interrupt sources
ETIMSK = 0x00; //extended timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
//主程序,判断按键值,并进行处理
void main(void)
{
unsigned char key_value;
init_devices();
while(1)
{
if(key_stime_ok) //每隔10ms进行检测是否按键按下
{
key_stime_ok=0;
key_value = read_key();
//判断是否有键按下
if (key_value != key_no) //判别键值并做相应的处理 key_no=0b11111111
{
switch (key_value)
{
case key_1:
//do samething
break;
case key_2:
//do samething
break;
case key_3:
//do samething
break;
case key_4:
//do samething
break;
case key_5:
PORTE ^= 1<<PE3; //led取反
break;
case key_6:
PORTE ^= 1<<PE2; //led取反
break;
case key_7:
PORTE ^= 1<<PE1; //led取反
break;
case key_8:
PORTE ^= 1<<PE0; //led取反
break;
}
}
}
}
}