八位LED灯左右各循环一次 按下按键1:数码管显示自己学号后八位 按下按键2:LED左移(每隔一个亮一个) 按下按键3:数码管左移显示自己学号最后一位 按下按键4:实现数码管999累加 按键按下可以实现实时中断
时间: 2023-05-26 21:07:46 浏览: 145
以下是该任务的示例代码:
```c
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned char led_state = 0; // LED的状态,0:左移,1:右移
volatile unsigned char display_state = 0; // 数码管的状态,0:数码管显示学号后八位,1:数码管显示学号最后一位
// 数码管显示的数字
unsigned char digits[10] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
};
// 将数码管的数字显示到数码管上
void display(unsigned short num)
{
static unsigned char digit_index = 0;
PORTD = digits[num % 10]; // 显示个位
PORTB |= 1 << digit_index; // 打开对应的数码管
_delay_us(100);
PORTB &= ~(1 << digit_index); // 关闭对应的数码管
digit_index = (digit_index + 1) % 3;
PORTD = digits[num % 100 / 10]; // 显示十位
PORTB |= 1 << digit_index;
_delay_us(100);
PORTB &= ~(1 << digit_index);
digit_index = (digit_index + 1) % 3;
PORTD = digits[num / 100]; // 显示百位
PORTB |= 1 << digit_index;
_delay_us(100);
PORTB &= ~(1 << digit_index);
digit_index = (digit_index + 1) % 3;
}
// LED左右循环
void led_cycle()
{
if (led_state == 0) { // 左移
static unsigned char led_index = 0;
PORTC &= ~(1 << led_index); // 关闭当前LED
led_index = (led_index + 1) % 8;
PORTC |= 1 << led_index; // 打开下一个LED
} else { // 右移
static unsigned char led_index = 7;
PORTC &= ~(1 << led_index); // 关闭当前LED
led_index = (led_index + 7) % 8;
PORTC |= 1 << led_index; // 打开下一个LED
}
}
// 数码管左移
void display_left_shift()
{
static unsigned short number = 12345678;
number = (number % 10000000) * 10 + (number / 10000000);
display(number);
}
// 数码管累加
void display_add()
{
static unsigned short number = 0;
number = (number + 1) % 1000;
display(number);
}
int main()
{
// 设置端口方向
DDRC = 0xFF; // LED端口
DDRD = 0xFF; // 数码管段选端口
DDRB = 0x07; // 数码管位选端口
// 初始化端口状态
PORTC = 0x01; // 给第一个LED点亮
display(0); // 数码管显示0
// 设置按键中断
sei(); // 全局中断使能
DDRD &= ~0x0F; // PD0~3设为输入
PORTD |= 0x0F; // PD0~3上拉
// 主循环
while (1) {
led_cycle(); // LED左右循环
if (display_state == 0) {
// 数码管显示学号后八位
display(12345678);
} else {
// 数码管显示学号最后一位
display(8);
}
_delay_ms(200);
if ((PIND & 0x01) == 0x00) { // 按键1
display_state = 0;
display(20190926);
_delay_ms(200);
} else if ((PIND & 0x02) == 0x00) { // 按键2
led_state = (led_state + 1) % 2;
_delay_ms(200);
} else if ((PIND & 0x04) == 0x00) { // 按键3
display_state = 1;
display_left_shift();
_delay_ms(200);
} else if ((PIND & 0x08) == 0x00) { // 按键4
display_add();
_delay_ms(200);
}
}
}
// 按键中断服务程序
ISR(INT0_vect)
{
if ((PIND & 0x01) == 0x00) { // 按键1
display_state = 0;
display(20190926);
} else if ((PIND & 0x02) == 0x00) { // 按键2
led_state = (led_state + 1) % 2;
} else if ((PIND & 0x04) == 0x00) { // 按键3
display_state = 1;
display_left_shift();
} else if ((PIND & 0x08) == 0x00) { // 按键4
display_add();
}
}
```
代码解释:
1. 定义了一个 `led_state` 变量和一个 `display_state` 变量,用于控制 LED 和数码管的状态;
2. 定义了一个 `digits` 数组,存储数字 0~9 在数码管上的显示形式;
3. 定义了一个 `display` 函数,用于将数字显示到数码管上;
4. 定义了一个 `led_cycle` 函数,用于实现 LED 的左右循环;
5. 定义了一个 `display_left_shift` 函数,用于实现数码管的左移;
6. 定义了一个 `display_add` 函数,用于实现数码管的累加;
7. 在 `main` 函数中初始化端口状态、设置按键中断,然后进入主循环;
8. 主循环中先调用 `led_cycle`、`display` 视情况显示相应数字,再延时 200 毫秒;
9. 判断按键状态,如果按下了相应的按键,则执行相应的逻辑;
10. 在 `INT0_vect` 中断服务程序中处理按键状态,调用相应的函数。
阅读全文