代码
// 定义第一个数码管引脚连接到Arduino的引脚号(共阴极数码管,不包含小数点引脚)
const int segmentPins1[] = {0, 1, 2, 3, 4, 5, 6};
// 定义第一个方向的三个灯(红、绿、黄)连接到Arduino的引脚号
const int ledPins1[] = {7, 8, 9};
// 定义第二个数码管引脚连接到Arduino的引脚号(共阴极数码管,不包含小数点引脚)
const int segmentPins2[] = {10, 11, 12, 13, 14, 15, 16};
// 定义第二个方向的三个灯(红、绿、黄)连接到Arduino的引脚号
const int ledPins2[] = {17, 18, 19};
//数码管显示数字对应的段码(共阴极),1 - d的显示编码
const unsigned char numCodes[] = {
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
0b01110111, // a
0b01111100, // b
0b00111001, // c
0b01011110 // d
};
unsigned char led_a_status = 0;
unsigned char led_a_time_all = 13;
unsigned char led_a_time_s_flag = 0;
unsigned char led_a_time_shalf_flag = 0;
unsigned char led_a_light_status = 1;
unsigned char led_b_status = 3;
unsigned char led_b_time_all = 13;
unsigned char led_b_time_s_flag = 0;
unsigned char led_b_time_shalf_flag = 0;
unsigned char led_b_light_status = 1;
// 定时器中断服务函数,每1毫秒触发一次
ISR(TIMER0_COMPA_vect) {
static unsigned int i = 0 , j = 0;
if(++i >= 500)
{
i = 0;
led_a_time_shalf_flag = 1;
led_b_time_shalf_flag = 1;
}
if(++j >= 1000)
{
j = 0;
led_a_time_s_flag = 1;
led_b_time_s_flag = 1;
}
}
void LedATimeProcess(void)
{
if(led_a_time_s_flag == 1)
{
led_a_time_s_flag = 0;
led_a_time_all --;
}
switch(led_a_status)
{
case 0:
if(led_a_time_all <= 6)
{
led_a_status = 1;
}
break;
case 1:
if(led_a_time_all <= 3)
{
led_a_status = 2;
}
break;
case 2:
if(led_a_time_all <= 0)
{
led_a_status = 3;
led_a_time_all = 13;
}
break;
case 3:
if(led_a_time_all <= 0)
{
led_a_status = 0;
led_a_time_all = 13;
}
break;
}
}
void LedBTimeProcess(void)
{
if(led_b_time_s_flag == 1)
{
led_b_time_s_flag = 0;
led_b_time_all --;
}
switch(led_b_status)
{
case 0:
if(led_b_time_all <= 6)
{
led_b_status = 1;
}
break;
case 1:
if(led_b_time_all <= 3)
{
led_b_status = 2;
}
break;
case 2:
if(led_b_time_all <= 0)
{
led_b_status = 3;
led_b_time_all = 13;
}
break;
case 3:
if(led_b_time_all <= 0)
{
led_b_status = 0;
led_b_time_all = 13;
}
break;
}
}
void LedARefresh(void)
{
if(led_a_time_shalf_flag == 1)
{
led_a_time_shalf_flag = 0;
led_a_light_status ^= 0x01;
}
switch(led_a_status)
{
case 0:
digitalWrite(ledPins1[0],LOW);
digitalWrite(ledPins1[1],HIGH);
digitalWrite(ledPins1[2],LOW);
break;
case 1:
digitalWrite(ledPins1[0],LOW);
if(led_a_light_status == 1)digitalWrite(ledPins1[1],HIGH);
else digitalWrite(ledPins1[1],LOW);
digitalWrite(ledPins1[2],LOW);
break;
case 2:
digitalWrite(ledPins1[0],LOW);
digitalWrite(ledPins1[1],LOW);
digitalWrite(ledPins1[2],HIGH);
break;
case 3:
digitalWrite(ledPins1[0],HIGH);
digitalWrite(ledPins1[1],LOW);
digitalWrite(ledPins1[2],LOW);
break;
}
}
void LedBRefresh(void)
{
if(led_b_time_shalf_flag == 1)
{
led_b_time_shalf_flag = 0;
led_b_light_status ^= 0x01;
}
switch(led_b_status)
{
case 0:
digitalWrite(ledPins2[0],LOW);
digitalWrite(ledPins2[1],HIGH);
digitalWrite(ledPins2[2],LOW);
break;
case 1:
digitalWrite(ledPins2[0],LOW);
if(led_b_light_status == 1)digitalWrite(ledPins2[1],HIGH);
else digitalWrite(ledPins2[1],LOW);
digitalWrite(ledPins2[2],LOW);
break;
case 2:
digitalWrite(ledPins2[0],LOW);
digitalWrite(ledPins2[1],LOW);
digitalWrite(ledPins2[2],HIGH);
break;
case 3:
digitalWrite(ledPins2[0],HIGH);
digitalWrite(ledPins2[1],LOW);
digitalWrite(ledPins2[2],LOW);
break;
}
}
void TubeARefresh(void)
{
switch(led_a_status)
{
case 0:
displayNumber(segmentPins1 ,led_a_time_all-3);
break;
case 1:
displayNumber(segmentPins1 ,led_a_time_all-3);
break;
case 2:
displayNumber(segmentPins1 ,led_a_time_all);
break;
case 3:
displayNumber(segmentPins1 ,led_a_time_all);
break;
}
}
void TubeBRefresh(void)
{
switch(led_b_status)
{
case 0:
displayNumber(segmentPins2 ,led_b_time_all-3);
break;
case 1:
displayNumber(segmentPins2 ,led_b_time_all-3);
break;
case 2:
displayNumber(segmentPins2 ,led_b_time_all);
break;
case 3:
displayNumber(segmentPins2 ,led_b_time_all);
break;
}
}
// 函数用于在给定的数码管上显示给定的数字
void displayNumber(int pins[], int number) {
if (number >= 1 && number <= 13) {
unsigned char code = numCodes[number-1];
for (int i = 0; i < 7; i++) {
digitalWrite(pins[i], bitRead(code, i));
}
}
}
// 函数用于使数码管闪烁显示给定的数字
void blink(int pins[], int number) {
for (int j = 0; j < 2; j++) {
displayNumber(pins, number);
// 这里去掉了delay,通过定时器中断来控制闪烁时间间隔
// delay(250);
clearDisplay(pins);
// 这里去掉了delay,通过定时器中断来控制闪烁时间间隔
// delay(250);
}
}
// 函数用于清除数码管显示(所有段熄灭)
void clearDisplay(int pins[]) {
for (int i = 0; i < 7; i++) {
digitalWrite(pins[i], LOW);
}
}
void setup() {
// 初始化第一个数码管引脚为输出模式
for (int i = 0; i < 7; i++) {
pinMode(segmentPins1[i], OUTPUT);
}
// 初始化第一个方向的灯引脚为输出模式
for (int i = 0; i < 3; i++) {
pinMode(ledPins1[i], OUTPUT);
}
// 初始化第二个数码管引脚为的输出模式
for (int i = 0; i < 7; i++) {
pinMode(segmentPins2[i], OUTPUT);
}
// 初始化第二个方向的灯引脚为输出模式
for (int i = 0; i < 3; i++) {
pinMode(ledPins2[i], OUTPUT);
}
// 设置定时器0
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
// 设置比较匹配值,每1毫秒触发一次中断
OCR0A = 156;
// 设置定时器模式为CTC(比较匹配时清零)
TCCR0A |= (1 << WGM01);
// 设置预分频器,这里选择64分频
TCCR0B |= (1 << CS01) | (1 << CS00);
// 使能定时器0中断
TIMSK0 |= (1 << OCIE0A);
}
void loop() {
LedATimeProcess();
LedBTimeProcess();
LedARefresh();
LedBRefresh();
TubeARefresh();
TubeBRefresh();
}
函数解释:(以下来自豆包AI)
一、变量定义部分
- 引脚定义:
- 定义了两组数码管和两组指示灯的引脚连接到 Arduino 的引脚号。
const int segmentPins1[]
和const int segmentPins2[]
分别定义了两个共阴极数码管(不包含小数点引脚)连接到 Arduino 的引脚数组。const int ledPins1[]
和const int ledPins2[]
分别定义了两个方向的三个灯(红、绿、黄)连接到 Arduino 的引脚数组。
- 数码管显示编码定义:
const unsigned char numCodes[]
定义了数码管显示数字(1 - d)对应的段码(共阴极)。每个元素对应一个数字或字符的显示编码,通过二进制数来表示数码管各段的亮灭状态,以便后续在数码管上正确显示相应内容。
- 指示灯状态及时间相关变量定义:
- 针对两个方向的指示灯(这里假设为
led_a
和led_b
),分别定义了一系列状态和时间相关的变量。 - 例如,
unsigned char led_a_status
等变量用于记录指示灯的当前状态(如亮灭、闪烁等不同状态模式),unsigned char led_a_time_all
等变量用于记录指示灯相关的时间总量,unsigned char led_a_time_s_flag
和unsigned char led_a_time_shalf_flag
等变量用于标记时间相关的事件是否发生(如经过 1 秒、经过 0.5 秒等),unsigned char led_a_light_status
等变量用于记录指示灯的亮灭状态(可能用于实现闪烁效果等)。
- 针对两个方向的指示灯(这里假设为
二、定时器中断服务函数
ISR(TIMER0_COMPA_vect)
函数:- 这是一个定时器中断服务函数,每 1 毫秒触发一次。
- 在函数内部,定义了两个静态变量
i
和j
,用于计数。 - 当
i
自增到 500(即经过 500 毫秒,也就是 0.5 秒)时,将i
重置为 0,并设置led_a_time_shalf_flag
和led_b_time_shalf_flag
为 1,表示经过了 0.5 秒这个时间节点,可能用于触发某些与 0.5 秒相关的操作,比如指示灯的闪烁切换等。 - 当
j
自增到 1000(即经过 1000 毫秒,也就是 1 秒)时,将j
重置为 0,并设置led_a_time_s_flag
和led_b_time_s_flag
为 1,表示经过了 1 秒这个时间节点,可能用于触发某些与 1 秒相关的操作,比如时间倒计时、状态切换等。
三、时间处理及状态更新函数
LedATimeProcess
函数:- 首先判断
led_a_time_s_flag
是否为 1,如果是,则表示经过了 1 秒,将该标志位清零,并将led_a_time_all
变量减 1,实现某种时间倒计时的效果。 - 然后根据
led_a_status
的不同取值,通过switch
语句进行不同的处理。例如,当led_a_status
为 0 时,如果led_a_time_all
剩余时间小于等于 6 秒,则将led_a_status
切换为 1;当led_a_status
为 1 时,如果led_a_time_all
剩余时间小于等于 3 秒,则将led_a_status
切换为 2;以此类推,通过不断根据剩余时间切换led_a_status
的值,实现不同状态之间的转换,可能对应着指示灯不同的显示模式或行为。
- 首先判断
LedBTimeProcess
函数:- 与
LedATimeProcess
函数类似,针对led_b
相关的时间和状态进行处理。先判断led_b_time_s_flag
是否为 1,若是则进行相应的时间递减操作,并根据led_b_status
的不同取值,通过switch
语句实现不同状态之间的转换,以控制led_b
相关的指示灯行为和时间倒计时效果。
- 与
四、指示灯刷新函数
LedARefresh
函数:- 首先判断
led_a_time_shalf_flag
是否为 1,如果是,则将该标志位清零,并通过led_a_light_status ^= 0x01
实现指示灯亮灭状态的切换(异或操作,每次执行都会改变当前亮灭状态)。 - 然后根据
led_a_status
的不同取值,通过switch
语句设置对应的ledPins1
引脚的输出电平,从而控制第一个方向的三个指示灯(红、绿、黄)的亮灭状态,实现不同状态下指示灯的正确显示。
- 首先判断
LedBRefresh
函数:- 与
LedARefresh
函数类似,先判断led_b_time_shalf_flag
是否为 1,进行相应的亮灭状态切换操作,然后根据led_b_status
的不同取值,通过switch
语句设置对应的ledPins2
引脚的输出电平,控制第二个方向的三个指示灯的亮灭状态。
- 与
五、数码管刷新函数
TubeARefresh
函数:- 根据
led_a_status
的不同取值,通过switch
语句调用displayNumber
函数在第一个数码管上显示不同的数字。例如,当led_a_status
为 0 或 1 时,显示led_a_time_all - 3
的值;当led_a_status
为 2 或 3 时,显示led_a_time_all
的值,通过这种方式在数码管上展示与led_a
相关的时间或其他信息。
- 根据
TubeBRefresh
函数:- 与
TubeARefresh
函数类似,根据led_b_status
的不同取值,通过switch
语句调用displayNumber
函数在第二个数码管上显示不同的数字,展示与led_b
相关的时间或其他信息。
- 与
六、数码管显示相关函数
displayNumber
函数:- 该函数用于在给定的数码管上显示给定的数字。
- 首先判断传入的数字
number
是否在有效范围内(1 到 13 之间),如果是,则从numCodes
数组中获取对应数字的段码code
。 - 然后通过循环遍历数码管的引脚数组
pins
,使用digitalWrite
函数根据段码中对应位的值(通过bitRead
函数获取)设置每个引脚的输出电平,从而在数码管上正确显示出相应的数字。
blink
函数:- 函数用于使数码管闪烁显示给定的数字。
- 通过循环两次,每次先调用
displayNumber
函数显示数字,然后调用clearDisplay
函数清除数码管显示(所有段熄灭),以此实现数码管的闪烁效果。这里原本可能有delay
函数用于控制闪烁时间间隔,但代码中去掉了,可能是通过定时器中断来控制闪烁时间间隔。
clearDisplay
函数:- 函数用于清除数码管显示(所有段熄灭)。
- 通过循环遍历数码管的引脚数组
pins
,使用digitalWrite
函数将每个引脚的输出电平设置为 LOW,从而使数码管所有段熄灭。
七、初始化函数 setup
- 引脚模式初始化:
- 分别对两组数码管和两组指示灯的引脚进行初始化,将它们设置为输出模式。
- 对于第一个数码管引脚数组
segmentPins1
的每个引脚,通过循环设置其引脚模式为OUTPUT
;同样对第一个方向的灯引脚数组ledPins1
、第二个数码管引脚数组segmentPins2
和第二个方向的灯引脚数组ledPins2
也进行了类似的初始化操作。
- 定时器 0 设置:
- 首先对定时器 0 的相关寄存器进行初始化操作,将
TCCR0A
和TCCR0B
设置为 0,将TCNT0
也设置为 0。 - 然后设置比较匹配值
OCR0A
为 156,这样当定时器 0 的计数值达到这个值时,就会触发比较匹配事件。 - 设置定时器模式为 CTC(比较匹配时清零),通过
TCCR0A |= (1 << WGM01)
实现。 - 设置预分频器为 64 分频,通过
TCCR0B |= (1 << CS01) | (1 << CS00)
实现。 - 最后使能定时器 0 中断,通过
TIMSK0 |= (1 << OCIE0A)
实现,使得定时器 0 每 1 毫秒触发一次中断服务函数ISR(TIMER0_COMPA_vect)
。
- 首先对定时器 0 的相关寄存器进行初始化操作,将
八、主循环函数 loop
- 主循环操作:
- 在主循环
loop
中,依次调用了LedATimeProcess
、LedBTimeProcess
、LedARefresh
、LedBRefresh
、TubeARefresh
和TubeBRefresh
函数。 - 通过不断循环执行这些函数,实现了对指示灯状态、时间的持续更新以及数码管显示内容的持续刷新,从而使整个系统能够根据设定的逻辑动态地展示相关信息和状态变化。
- 在主循环
总体而言,这段代码实现了一个基于 Arduino 的系统,通过定时器中断来控制时间相关的操作,实现了两个方向的指示灯和两个数码管的协同工作,能够根据不同的状态和时间条件展示不同的信息,比如倒计时、状态切换以及相应的数码管显示等功能。