原题目
识别多个按键的输入情况,并控制蜂鸣器鸣叫。以K1、K2的状态表示2位二进制数(按下表示“1”,未按表示“0”,且K1对应低位)。若该二进制数中有奇数个“1”,则蜂鸣器以1秒(定时器中断实现)的间隔鸣叫,同时点亮LED1;若该二进制数中有偶数个“1”,则蜂鸣器以2秒(定时器中断实现)的间隔鸣叫,同时点亮LED1和LED2。K3按下时,蜂鸣器以1秒(定时器中断实现)的间隔鸣叫对应的次数,同时四个LED灯(LED1~LED4)以相同的频率闪烁对应的次数,之后蜂鸣器停止鸣叫,所有LED保持常亮。K4按下时,清除按键状态,所有LED熄灭,并关闭蜂鸣器,系统进入初始状态。
总体思想:利用定时器每个计数周期触发一次中断的特性来设计时间标志timer,
并设计主程序通过轮询的方式查询按键事件。
根据对题意的理解,我们小组商议决定把题目描述归纳为4种模式,这4种模式分别以整形变量flag=1、2、3、4记录。
flag=1代表按下了奇数个“1”,设置GPKDAT = 0xef使LED1点亮。
flag=2代表按下了偶数个“1”,设置GPKDAT = 0xcf使LED1和LED2点亮。
flag=3代表K3按下,在delay(300000)前后分别设置GPKDAT = 0x0f,GPKDAT = 0xff
实现题目要求的“四个LED灯(LED1~LED4)以相同的频率闪烁对应的次数,之后蜂鸣器停止鸣叫,
所有LED保持常亮。”
flag=4代表K4按下,设置GPKDAT = 0xff,使所用LED灯熄灭,同时设置number=0b00,number_turn=0b00
,count=0清除按键状态。
中断处理函数内设置计数器timer,主函数内定时器初始化,用flag标记此时对应的状态,再对应按键的处理中,
亮灯功能的实现依靠改变GPKDATA的值实现,闪烁判断通过timer的周期性改变GPKDATA的值实现。
通过timer_init()设置定时器1秒或2秒,从而实现题目对蜂鸣器鸣叫的控制要求。
现题目
设计要求:
识别多个按键的输入情况,并控制蜂鸣器按不同的模式鸣叫。①以K2、K3的状态表示两位二进制数 (K2为最低位,按下表示 “1”,未按表示 “0”)。当按键按下时,对应的LED灯点亮,用于标识输入内 容。② K1按下时,若该二进制数中有奇数个 “1”,则蜂鸣器以1秒(定时器中断实现)的间隔鸣叫该二 进制数对应的次数,同时LED1和LED3以相同的频率闪烁对应的次数:若该二进制数中有偶数个 “1”,则 蜂鸣器以0.5秒(定时器中断实现)的间隔鸣叫,同时四个LED灯(LED1~LED4)按相同频率从LED1到LED4 逐一点亮(同一个时刻只有一个灯亮),并循环显示。③ K4按下时,清除按键状态,所有LED灯熄灭,并 关闭蜂鸣器,系统进入初始状态。
■ 说明:若采用查询方式判断按键是否按下,在程序中注意对按键的实时响应处理(即任意一个按键按 下后,程序能立即执行对应的功能操作)。LED灯亮1次+灭1次视为闪烁1次。蜂鸣器通过GPF14作为输出口 进行控制,输出高电平鸣叫,输出低电平关闭。未特别要求定时器中断实现的时间间隔,均可通过软件延 时实现。
希望给出更改后的代码并注释,说明更改思路
环境
硬件:Tiny6410嵌入式实验平台。
软件:PC机操作系统Fedora/CentOS+minicom+ARM-Linux 开发环境
main.c
#include "stdio.h"
#define GPKCON0 (*(volatile unsigned long *)0x7F008800)
#define GPKDAT (*(volatile unsigned long *)0x7F008808)
#define GPNCON (*(volatile unsigned long *)0x7F008830)
#define GPNDAT (*(volatile unsigned long *)0x7F008834)
#define GPKCON0 (*((volatile unsigned long *)0x7F008800))
#define GPKDATA (*((volatile unsigned long *)0x7F008808))
#define EINT0CON0 (*((volatile unsigned long *)0x7F008900))
#define EINT0MASK (*((volatile unsigned long *)0x7F008920))
#define EINT0PEND (*((volatile unsigned long *)0x7F008924))
#define PRIORITY (*((volatile unsigned long *)0x7F008280))
#define SERVICE (*((volatile unsigned long *)0x7F008284))
#define SERVICEPEND (*((volatile unsigned long *)0x7F008288))
#define VIC0IRQSTATUS (*((volatile unsigned long *)0x71200000))
#define VIC0FIQSTATUS (*((volatile unsigned long *)0x71200004))
#define VIC0RAWINTR (*((volatile unsigned long *)0x71200008))
#define VIC0INTSELECT (*((volatile unsigned long *)0x7120000c))
#define VIC0INTENABLE (*((volatile unsigned long *)0x71200010))
#define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014))
#define VIC0PROTECTION (*((volatile unsigned long *)0x71200020))
#define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024))
#define VIC0PRIORITYDAISY (*((volatile unsigned long *)0x71200028))
#define VIC0ADDRESS (*((volatile unsigned long *)0x71200f00))
#define PWMTIMER_BASE (0x7F006000)
#define TCFG0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x00)) )
#define TCFG1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x04)) )
#define TCON ( *((volatile unsigned long *)(PWMTIMER_BASE+0x08)) )
#define TCNTB0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x0C)) )
#define TCMPB0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x10)) )
#define TCNTO0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x14)) )
#define TCNTB1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x18)) )
#define TCMPB1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x1C)) )
#define TCNTO1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x20)) )
#define TCNTB2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x24)) )
#define TCMPB2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x28)) )
#define TCNTO2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x2C)) )
#define TCNTB3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x30)) )
#define TCMPB3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x34)) )
#define TCNTO3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x38)) )
#define TCNTB4 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x3C)) )
#define TCNTO4 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x40)) )
#define TINT_CSTAT ( *((volatile unsigned long *)(PWMTIMER_BASE+0x44)) )
#define GPFCON (*(volatile unsigned int *)0x7F0080A0)
#define GPFDAT (*(volatile unsigned int *)0x7F0080A4)
void timer_init(unsigned long utimer,unsigned long uprescaler,unsigned long udivider,unsigned long utcntb,unsigned long utcmpb);
int flag = 0; //模式
int count = 0; //次数
int dat = 0; //按下的键
int number = 0b00; //二进制数number预设为00
int number_turn = 0b00; //二进制数number预设为00
typedef void (isr) (void);
extern void asm_timer_irq();
void buzzer_on() //蜂鸣器开
{
GPFDAT |= 1<<14;
}
void buzzer_off() //蜂鸣器关
{
GPFDAT &= ~(1<<14);
}
void buzzer_init(void) //蜂鸣器初始化
{
// set GPF14 as output
GPFCON |= 1<<28;
GPFCON &= ~(1<<29);
}
void delay(volatile int i) //延时函数(volatile防止代码被优化,强制执行i次)
{
while(i--);
}
void irq_init(void) //中断初始化
{
/* 在中断控制器里使能timer0中断 */
VIC0INTENABLE |= (1<<23);
VIC0INTSELECT =0;
isr** isr_array = (isr**)(0x7120015C);
isr_array[0] = (isr*)asm_timer_irq;
/*将GPK4-GPK7配置为输出口*/
GPKCON0 = 0x11110000;
/*熄灭四个LED灯*/
GPKDATA = 0xff;
}
// timer0中断的中断处理函数
void do_irq()
{
unsigned long uTmp;
//清timer0的中断状态寄存器
uTmp = TINT_CSTAT;
TINT_CSTAT = uTmp;
VIC0ADDRESS=0x0;
if(flag==3)
{
if(count>0)
{
buzzer_on();
GPKDAT = 0x0f;
delay(300000);
buzzer_off();
GPKDAT = 0xff; //所有LED熄灭
count--;
}
else
{
GPKDAT = 0x0f;
}
}
if(flag==1)
{
buzzer_on();
delay(300000);
buzzer_off();
GPKDAT = 0xef;
}
if(flag==2)
{
buzzer_on();
delay(300000);
buzzer_off();
GPKDAT = 0xcf;
}
if(flag==4)
{
flag=0;
GPKDAT = 0xff; //所有LED熄灭
buzzer_off(); //关闭buzzer
}
}
// 初始化timer
void timer_init(unsigned long utimer,unsigned long uprescaler,unsigned long udivider,unsigned long utcntb,unsigned long utcmpb)
{
unsigned long temp0;
// 定时器的输入时钟 = PCLK / ( {prescaler value + 1} ) / {divider value} = PCLK/(65+1)/16=62500hz
//设置预分频系数为66
temp0 = TCFG0;
temp0 = (temp0 & (~(0xff00ff))) | (uprescaler<<0);
TCFG0 = temp0;
// 16分频
temp0 = TCFG1;
temp0 = (temp0 & (~(0xf<<4*utimer))& (~(1<<20))) |(udivider<<4*utimer);
TCFG1 = temp0;
// 1s = 62500hz
TCNTB0 = utcntb;
TCMPB0 = utcmpb;
// 手动更新
TCON |= 1<<1;
// 清手动更新位
TCON &= ~(1<<1);
// 自动加载和启动timer0
TCON |= (1<<0)|(1<<3);
// 使能timer0中断
temp0 = TINT_CSTAT;
temp0 = (temp0 & (~(1<<utimer)))|(1<<(utimer));
TINT_CSTAT = temp0;
}
int main()
{
buzzer_init();
int i=0;
while (1)
{
// 轮询的方式查询按键事件
dat = GPNDAT; //记录按键状态
if(!(dat & (1<<2))) // KEY3被按下
{
flag=3;
count = number;
}
if(!(dat & (1<<0))) // KEY1被按下,设置二进制数低位为1
{
number |= 0b01;
number_turn = ((number & 0b10)>>1) | ((number & 0b01)<<1); //形成K1K2
}
if(!(dat & (1<<1))) // KEY2被按下,设置二进制数高位为1
{
number |= 0b10;
number_turn = ((number & 0b10)>>1) | ((number & 0b01)<<1); //形成K1K2
}
if(flag==3)
{
timer_init(0,65,4,62500,0); //定时器设置为2s
}
else if(number == number_turn) //二进制数中有偶数个1
{
flag=2;
timer_init(0,65,4,62500*2,0); //定时器设置为2s
}
else
{
flag=1;
timer_init(0,65,4,62500,0); //定时器设置为2s
}
if(!(dat & (1<<3))) // KEY4被按下
{
flag=4;
number=0b00;
number_turn=0b00;
count=0;
timer_init(0,65,4,62500,0); //定时器设置为1s
}
}
return 0;
}
源于chatGPT仅供参考
以下是一个嵌入式代码实现的示例,用于识别多个按键输入情况,并控制蜂鸣器和LED的状态。请注意,这是一个基本的示例,您可能需要根据具体硬件平台和使用的编程语言进行适当的修改。
```cpp
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL // 设置主频16MHz
#include <util/delay.h>
volatile uint8_t keyState = 0; // 按键状态变量
void initialize()
{
// 初始化IO口和定时器
// 配置按键引脚为输入, K1-K4分别连接到PD0-PD3
DDRD &= ~(1 << PORTD0) & ~(1 << PORTD1) & ~(1 << PORTD2) & ~(1 << PORTD3);
// 启用上拉电阻
PORTD |= (1 << PORTD0) | (1 << PORTD1) | (1 << PORTD2) | (1 << PORTD3);
// 配置LED引脚为输出, LED1-LED4分别连接到PB0-PB3
DDRB |= (1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2) | (1 << PORTB3);
// 配置蜂鸣器引脚为输出, 连接到PC0
DDRC |= (1 << PORTC0);
// 配置定时器0, 使用CTC模式
TCCR0A = (1 << WGM01);
// 设置定时器0的计数值,用于不同频率的蜂鸣器和LED闪烁
OCR0A = 15; // 16MHz / (2 * 256 * (15 + 1)) = 520Hz
// 启用定时器0的比较匹配中断
TIMSK0 |= (1 << OCIE0A);
// 允许中断
sei();
}
// 获取按键状态
uint8_t readKeys()
{
// 使用位掩码读取按键状态
uint8_t keys = PIND & 0x0F;
return keys;
}
// 判断二进制数中1的个数是奇数还是偶数
bool isOdd(uint8_t num)
{
int count = 0;
while (num) {
count += num & 1;
num >>= 1;
}
return count % 2 != 0;
}
void toggleLEDs()
{
// 根据按键状态点亮或熄灭LED
if (keyState == 0) {
PORTB &= ~(1 << PORTB0) & ~(1 << PORTB1) & ~(1 << PORTB2) & ~(1 << PORTB3);
} else {
PORTB |= (1 << PORTB0);
if (!isOdd(keyState)) {
PORTB |= (1 << PORTB1);
}
}
}
void toggleBuzzer(bool state)
{
if (state) {
PORTC |= (1 << PORTC0);
} else {
PORTC &= ~(1 << PORTC0);
}
}
void toggleLEDsWithBuzzer(uint8_t count)
{
for (int i = 0; i < count; i++) {
PORTB ^= (1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2) | (1 << PORTB3);
_delay_ms(500);
}
}
// 定时器中断处理程序
ISR(TIMER0_COMPA_vect)
{
static uint16_t timerCount = 0;
static bool buzzerState = false;
timerCount++;
// 每隔1秒或2秒更新蜂鸣器状态
if (timerCount >= 520) {
timerCount = 0;
// 根据按键状态和计时器间隔设置蜂鸣器状态
if (keyState != 0) {
if (isOdd(keyState)) {
toggleBuzzer(buzzerState);
buzzerState = !buzzerState;
} else {
toggleBuzzer(true);
你用Tiny6410这种ARM11芯片就做几个按键和led,真够浪费资源的