问题描述
因此,任务是使LED多次闪烁,具体取决于所按下的按钮,例如如果按下sw3,LED必须闪烁3秒钟,并每1/4秒产生一次中断。
如果按下任何按钮,是否有任何激活计时器的方法?并且只要计时器正在运行就不应该读取按钮?
我已经编写了以下代码,但是我不确定它是否可以在实验室中正常工作,因此如果有任何人可以提供帮助,那就太好了。将不胜感激。谢谢。
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDs PORTB
#define KEYs PORTA
#define OUTPUT 0b11111111
#define INPUT 0b00000000
volatile uint8_t count = 0;
volatile uint8_t ready = 0;
volatile uint8_t seconds;
void set_up_the_timer(void);
void blink_or_flash(void);
int main(void)
{
DDRA = INPUT;
DDRB = OUTPUT;
LEDs = 0xFF;
if(!(PINA & (1 << PINA0))) {
set_up_the_timer();
sei();
}
while (1)
{
switch(KEYs) {
case 0b11111110:
seconds = 7; // 0.15 * 7 = 1.05s
blink_or_flash();
break;
case 0b11111101:
seconds = 13; // 0.15 * 13 = 1.95s;
blink_or_flash();
break;
case 0b11111011:
seconds = 20; // 0.15 * 20 = 3s;
blink_or_flash();
break;
case 0b11110111:
seconds = 27; // 0.15 * 27 = 4.05s
blink_or_flash();
break;
case 0b11101111:
seconds = 33; // 0.15 * 33 = 4.95s
blink_or_flash();
break;
case 0b11011111:
seconds = 40; // 0.15 * 40 = 60s
blink_or_flash();
break;
case 0b10111111:
seconds = 47; // 0.15 * 47 = 7.05s
blink_or_flash();
break;
case 0b01111111:
seconds = 53; // 0.15 * 53 = 7.95s
blink_or_flash();
break;
default:
break;
}
}
}
void set_up_the_timer() {
TCCR1A |= (1 << WGM12);
OCR1A = 2344; // an interrupt occurring every 0.15 second
TimsK1 |= (1 << OCIE1A);
TCCR1B |= (1 << CS12) | (1 << CS10);
}
void blink_or_flash() {
if(ready == 1) {
LEDs = 0x00;
count = 0;
}
}
ISR(TIMER0_COMPA_vect) {
count++;
LEDs = ~(LEDs);
if(count >= seconds) {
ready = 1;
}
}
解决方法
我不确定我对您的问题的解释是否正确,但这也许有帮助:
// Datasheet
// https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf
// Not necessary but important for calculations
#define F_CPU 16000000UL
#define HIGH 0xFF
#define LOW 0x00
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned char loop = 0;
volatile unsigned long counter = 0; // Need be of type long to prevent overflow
volatile unsigned long milliseconds; // Need be of type long to prevent overflow
void timer_setup(void);
void timer_start();
void timer_stop();
void timer_blink(void);
ISR(TIMER1_COMPA_vect)
{
PORTB = ~(PORTB);
counter++;
if(counter > milliseconds)
loop = 1;
}
int main(void)
{
// Setup PORTA to input (no pullup resitors)
// @startup alle pins on the controller are inputs,// so setup pins as input can be omitted
DDRA = LOW;
// Setup PORTB to output and switch all LEDs on
DDRB = HIGH;
PORTB = HIGH;
timer_setup();
while (1)
{
switch(PINA) {
case 0b11111110: milliseconds = 1005; // 1.05s
timer_blink();
break;
case 0b11111101: milliseconds = 1950; // 1.95s;
timer_blink();
break;
case 0b11111011: milliseconds = 3000; // 3s;
timer_blink();
break;
case 0b11110111: milliseconds = 4050; // 4.05s
timer_blink();
break;
case 0b11101111: milliseconds = 4950; // 4.95s
timer_blink();
break;
case 0b11011111: milliseconds = 60000; // 60s
timer_blink();
break;
case 0b10111111: milliseconds = 7005; // 7.05
timer_blink();
break;
case 0b01111111: milliseconds = 7950; // 7.95
timer_blink();
break;
default:
break;
}
}
}
void timer_setup()
{
// Timer 1 (16 Bit)
// Mode: CTC
// Prescaler: 64 (will be accurate because there is no remainder @datasheet page 146)
// Compare match: F_CPU 16000000 Hz
// OCR1A = -------------------- - 1 = -------------- = 249
// 1 1
// ------- * PRESCALER ------- * 64
// T_INT 0.001 s
// Control: Compare Match Interrupt every 1 ms
OCR1A = 249;
TCCR1A = (1<<WGM12);
TIMSK1 = (1 << OCIE1A);
sei();
}
void timer_start()
{
TCNT1 = 0;
TCCR1B |= (1<<CS11) | (1<<CS10);
TCCR1B &= ~(1<<CS12);
}
void timer_stop()
{
TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10));
TCNT1 = 0;
}
void timer_blink()
{
loop = 0;
counter = 0;
timer_start();
// Wait until sequence ended
while(loop != 1)
asm volatile("NOP");
timer_stop();
// Reset LEDs
PORTB = 0x00;
}
目前我无法测试解决方案,因此可能存在一些错误...