1.实验任务
编写控制程序,要求:
(1)两个按键L/R,分别连接外部中断0和外部中断1;
(2)数码管初始显示:01234567;
(3)当用户按下L按键时,数码管显示的数据向左移动;
(4)当用户按下R按键时,数码管显示的数据向右移动。
注意事项:按键不松开数据不更新,仍然显示原数据。
2.实验原理
2.1硬件原理与连线图
1.外部中断与独立按键连线图,如图1所示。
图1 独立按键电路原理图
2.数码管连线图,如图2所示。
图2 数码管动态显示电路原理图
【注意】一定要按本图所示的连线编写控制程序。
该回答引用于gpt与OKX安生共同编写:
好的,以下是8051单片机控制7段数码管外部中断的具体步骤:
1.定义和初始化变量
首先需要定义和初始化一些变量来存储当前显示的值以及左右移位的状态。还需要定义一个查找表来将数字映射到其对应的段模式。
2.配置外部中断引脚和使能中断
将L和R按键连接到外部中断0和外部中断1引脚,然后使用P3寄存器将这些引脚配置为输入。设置IE寄存器的相应位以启用中断。
3.初始化7段数码管
将每个段的引脚连接到单片机的IO口,并将这些IO口配置为输出。然后可以通过设置每个IO口的状态来显示初始值“01234567”。
4.实现中断服务程序
当外部中断触发时,执行中断服务程序。在中断服务程序中,需要首先检测哪个按键被按下。如果是左键,则将当前显示的值向左移动一个数字,并更新显示。如果是右键,则将当前显示的值向右移动一个数字,并更新显示。需要注意去抖动逻辑,避免单次按键触发多次中断。
5.主程序
在主程序中,需要无限循环等待中断的发生。同时,在中断服务程序中更新了显示后,需要将更新后的值存储到缓冲区中,以便下一次更新时使用。
希望这些步骤能够帮助您实现在8051单片机上使用外部中断控制7段数码管的功能。
您可以参考一下:
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
// 数字到段模式的查找表
uchar code segTable[] = {
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
// 存储当前显示的值、缓冲区和左右移位状态的变量
uchar curValue = 0, buffer[8] = {0}, leftShift = 0, rightShift = 0;
// 初始化IO口和中断
void init() {
P3 = 0xFF; // 将P3设为输入
IE = 0x85; // 启用INT0和INT1中断
IT0 = 1; // 设定INT0中断触发方式为下降沿
IT1 = 1; // 设定INT1中断触发方式为下降沿
}
// 显示数字
void display(uchar digit) {
P1 = segTable[digit]; // 设置IO口状态
delay(); // 延时一段时间,以便眼睛观察到数码管的变化
}
// 更新并显示数码管
void updateDisplay() {
// 将当前值存储到缓冲区中
buffer[curValue] = curValue;
// 如果需要左移,则将缓冲区向左移动一位
if (leftShift) {
for (uint i = 1; i < 8; i++) {
buffer[i - 1] = buffer[i];
}
leftShift = 0; // 清除左移标志位
}
// 如果需要右移,则将缓冲区向右移动一位
if (rightShift) {
for (uint i = 7; i > 0; i--) {
buffer[i] = buffer[i - 1];
}
rightShift = 0; // 清除右移标志位
}
// 显示缓冲区中的值
for (uint i = 0; i < 8; i++) {
display(buffer[i]);
}
}
// 左移函数
void leftShiftHandler() interrupt 0 {
leftShift = 1;
}
// 右移函数
void rightShiftHandler() interrupt 2 {
rightShift = 1;
}
// 延时函数
void delay() {
uchar i, j;
for (i = 255; i > 0; i--)
for (j = 110; j > 0; j--);
}
// 主函数
void main() {
init(); // 初始化
while (1) { // 无限循环
updateDisplay(); // 更新并显示数码管
}
}
需要根据您的实际硬件配置和需求进行调整和修改。希望能对您有所帮助!
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
这个任务可以使用中断来实现:当L按键按下时触发外部中断0,R按键按下时触发外部中断1。代码中可以使用滚动变量,表示当前数码管显示的数据是哪一位开始的。当触发外部中断0时,滚动变量加1,当触发外部中断1时,滚动变量减1,然后更新数码管的显示。
下面是这个任务的控制程序代码,通过 Keil C 编写。需要头文件 stm8s.h 和 stm8s_gpio.h,另外还需要初始化 GPIO 和外部中断:
#include "stm8s.h"已黑化的小白 #include "stm8s_gpio.h"已黑化的小白
// 定义数码管的引脚
#define SEG_A GPIO_PIN_1
#define SEG_B GPIO_PIN_2
#define SEG_C GPIO_PIN_3
#define SEG_D GPIO_PIN_4
#define SEG_E GPIO_PIN_5
#define SEG_F GPIO_PIN_6
#define SEG_G GPIO_PIN_7
#define SEG_DP GPIO_PIN_0
// 定义数码管的数字数据
const uint8_t digit[] = {
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // 0
SEG_B | SEG_C, // 1
SEG_A | SEG_B | SEG_G | SEG_E | SEG_D, // 2
SEG_A | SEG_B | SEG_C | SEG_D | SEG_G, // 3
SEG_B | SEG_C | SEG_F | SEG_G, // 4
SEG_A | SEG_F | SEG_G | SEG_C | SEG_D, // 5
SEG_A | SEG_F | SEG_G | SEG_C | SEG_D | SEG_E, // 6
SEG_A | SEG_B | SEG_C, // 7
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G, // 8
SEG_A | SEG_B | SEG_C | SEG_F | SEG_G // 9
};
// 定义数码管的状态
uint8_t display[8] = { 2, 1, 0, 3, 4, 5, 6, 7 };
uint8_t display_pos = 0;
// 外部中断0中断服务程序
INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 2) {
if (GPIO_ReadInputData(GPIOA) & GPIO_PIN_3) { // 检查按键是否按下
display_pos++; // 滚动变量加1
display_pos %= 8;
}
// 清除中断标记
EXTI_ClearITPendingBit(EXTI_IT_Pin3);
}
// 外部中断1中断服务程序
INTERRUPT_HANDLER(EXTI_PORTB_IRQHandler, 4) {
if (GPIO_ReadInputData(GPIOB) & GPIO_PIN_4) { // 检查按键是否按下
display_pos--; // 滚动变量减1
display_pos &= 0x7;
}
// 清除中断标记
EXTI_ClearITPendingBit(EXTI_IT_Pin4);
}
// 数码管显示函数
void display_digit(uint8_t pos) {
// 设置数码管的引脚状态
GPIO_WriteLow(GPIOD, DIGIT_1 | DIGIT_2 | DIGIT_3 | DIGIT_4);
GPIO_WriteHigh(GPIOD, (1 << pos));
uint8_t value = display[pos];
GPIO_WriteLow(GPIOC, SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);
GPIO_WriteHigh(GPIOC, digit[value]);
}
int main(void) {
// 初始化GPIO
GPIO_Init(GPIOD, (DIGIT_1 | DIGIT_2 | DIGIT_3 | DIGIT_4), GPIO_MODE_OUT_PP_LOW_FAST);
GPIO_Init(GPIOC, (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP), GPIO_MODE_OUT_PP_LOW_FAST);
GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_IN_FL_IT); // 外部中断0连接PA3
GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_IN_FL_IT); // 外部中断1连接PB4
EXTI_SetPinSensitivity(EXTI_PIN_3, EXTI_SENSITIVITY_FALL_ONLY);
EXTI_SetPinSensitivity(EXTI_PIN_4, EXTI_SENSITIVITY_FALL_ONLY);
enableInterrupts(); // 开启全局中断
while (1) {
// 数码管显示
for (uint8_t i = 0; i < 8; i++) {
display_digit(i);
for (uint16_t j = 0; j < 1000; j++);
}
}
}
这个任务实现的核心是利用了单片机的外部中断和数码管动态显示原理。
外部中断可以响应外部信号的变化,并且可以立即将处理器转移到中断服务程序中执行。在这个任务中,外部中断0和中断1的触发信号来自两个按键,分别连接到了单片机的PA3和PB4引脚。当按键按下时,相应的引脚被拉低,触发中断;当按键松开时,相应的引脚被拉高,中断被取消。
数码管动态显示原理采用了扫描显示技术。一个数码管显示器通常由多个发光二极管(LED)和一个集合极(共阴极或共阳极)组成。在多个数码管显示器中,要显示的那个数码管会通过集合极被选中,其他的数码管会被关闭。每个数码管需要一个数字信号来指示在当前显示框中显示哪个数字。在一次扫描过程中,所有的数码管都被轮流选中,并且它们里面的数字信号相继变化,以便将正确的数字显示到正确的位置。
在本实验中,使用了一个常见的数码管动态显示方案,它使用了四个共阴极数码管,每个数码管连接了一个GPIO口。在程序中,表示数码管当前显示哪个位置的变量 display_pos 会随着用户按键的操作而改变,最终数码管会显示相应的更新后的数字。
如果我的回答解决了您的问题,请采纳!
简要回答 提前将数组写好 中断配置好 再中断程序中加个判断判断按键是否松开松开后进入for循环对数组进行移位 输出即可
不知道你这个问题是否已经解决, 如果还没有解决的话:需要根据MCU资源才能最终确定,需求规划直接购买商用部件的有超声波、舵机、声控、摄像头等,在设计时要考虑PIN-TO-PIN直插,并且留够安装孔。