使用国产仿真平台SmartEDA,进行Arduino仿真设计之简易红绿灯设计(二)
效果图
效果:
代码:
// 定义第一个数码管引脚连接到Arduino的引脚号(共阴极数码管,不包含小数点引脚)
const int segmentPins1[] = {0, 1, 2, 3, 4, 5, 6};
// 定义第一个方向的三个灯(红、绿、黄)连接到Arduino的引脚号
const int ledPins1[4][3] = {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ,18 };
//数码管显示数字对应的段码(共阴极),1 - d的显示编码
const unsigned char numCodes[] = {
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
};
unsigned char led_status = 0; // 当前的方向状态机
unsigned char led_light_status = 2; // 用于记录第某个方向相关的灯的状态
unsigned char led_time_all = 12; // 用于记录第一个方向相关的灯的总时间,初始值为13,单位为秒
unsigned char led_time_s_flag = 0; // 是否达到一秒的时间间隔的标志位
unsigned char led_time_shalf_flag = 0; // 是否达到半秒的时间间隔标志位,初始值为0,达到时会被设置为1
ISR(TIMER0_COMPA_vect);
void LedTimeProcess(void);
void LedRefresh(void);
void TubeRefresh(void);
void displayNumber(int pins[], int number) ;
void setup()
{
// 初始化第一个数码管引脚为输出模式
for (int i = 0; i < 7; i++)
{
pinMode(segmentPins1[i], OUTPUT);
}
// 初始化第一个方向的灯引脚为输出模式
for (int i = 0; i < 4; i++)
{
for(int j = 0; j < 3; j++)
{
pinMode(ledPins1[i][j], OUTPUT);
}
}
// 设置定时器0
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
// 设置比较匹配值,每1毫秒触发一次中断
OCR0A = 125;
// 设置定时器模式为CTC(比较匹配时清零)
TCCR0A |= (1 << WGM01);
// 设置预分频器,这里选择64分频
TCCR0B |= (1 << CS01) | (1 << CS00);
// 使能定时器0中断
TIMSK0 |= (1 << OCIE0A);
// 开启全局中断使能,确保定时器中断能够被响应
sei();
}
void loop()
{
LedTimeProcess();
LedRefresh();
TubeRefresh();
}
// 定时器中断服务函数,每1毫秒触发一次
ISR(TIMER0_COMPA_vect)
{
static unsigned int i = 0;
if(++i >= 1000)
{
i = 0;
led_time_s_flag = 1;
}
}
void LedTimeProcess(void)
{
if(led_time_s_flag == 1)
{
led_time_s_flag = 0;
if(--led_time_all <= 0)
{
led_time_all = 12;
led_light_status = 2;
if(++led_status >= 4)
{
led_status = 0;
}
}
switch(led_light_status)
{
case 0:
break;
case 1:
break;
case 2:
if(led_time_all<=3)
{
led_light_status = 1;
}
break;
}
}
}
void LedRefresh(void)
{
for(int i = 0; i < 4; i++)
{
if(i == led_status)
{
switch(led_light_status)
{
case 0:
digitalWrite(ledPins1[i][0], HIGH);
digitalWrite(ledPins1[i][1], LOW);
digitalWrite(ledPins1[i][2], LOW);
break;
case 1:
digitalWrite(ledPins1[i][0], LOW);
digitalWrite(ledPins1[i][1], LOW);
digitalWrite(ledPins1[i][2], HIGH);
break;
case 2:
digitalWrite(ledPins1[i][0], LOW);
digitalWrite(ledPins1[i][1], HIGH);
digitalWrite(ledPins1[i][2], LOW);
break;
}
}
else
{
digitalWrite(ledPins1[i][0], HIGH);
digitalWrite(ledPins1[i][1], LOW);
digitalWrite(ledPins1[i][2], LOW);
}
}
}
void TubeRefresh(void)
{
switch(led_light_status)
{
case 0:
break;
case 1:
displayNumber(segmentPins1 , led_time_all);
break;
case 2:
displayNumber(segmentPins1 , led_time_all-3);
break;
}
}
// 函数用于在给定的数码管上显示给定的数字
void displayNumber(int pins[], int number)
{
if (number >= 1 && number <= 9)
{
unsigned char code = numCodes[number-1];
for (int i = 0; i < 7; i++)
{
digitalWrite(pins[i], bitRead(code, i));
}
}
}
代码阐述:
一、硬件连接定义
- 定义了一个共阴极数码管连接到 Arduino 的引脚数组
segmentPins1
,以及一个二维数组ledPins1
用于表示四个方向每组三个灯(红、绿、黄)连接到 Arduino 的引脚号。 - 还定义了数码管显示数字(1 - 9)对应的共阴极段码数组
numCodes
。
二、状态及时间相关变量
- 声明了一些变量用于记录状态和时间信息,如方向状态机
led_status
、灯的状态led_light_status
、灯的总时间led_time_all
以及用于标记一秒和半秒时间间隔的标志位led_time_s_flag
和led_time_shalf_flag
。
三、函数声明
- 声明了定时器中断服务函数
ISR(TIMER0_COMPA_vect)
、时间处理函数LedTimeProcess
、指示灯刷新函数LedRefresh
、数码管刷新函数TubeRefresh
以及数码管显示数字函数displayNumber
。
四、初始化函数setup
- 初始化数码管引脚和灯引脚为输出模式。
- 设置定时器 0 的相关参数,包括清零、设置比较匹配值、选择定时器模式及预分频器,最后使能定时器 0 中断并开启全局中断使能。
五、主循环函数loop
- 在主循环中依次调用
LedTimeProcess
、LedRefresh
和TubeRefresh
函数,以持续更新状态和刷新显示。
六、具体函数实现
ISR(TIMER0_COMPA_vect)
:定时器中断服务函数,每 1 毫秒触发一次,当计数达到 1000(即 1 秒)时设置led_time_s_flag
为 1。LedTimeProcess
:根据led_time_s_flag
判断是否达到一秒间隔,进行时间递减、状态切换等操作,如时间归零时重置并更新led_status
和led_light_status
。LedRefresh
:根据led_status
和led_light_status
设置对应ledPins1
引脚的输出电平,控制指示灯亮灭。TubeRefresh
:根据led_light_status
调用displayNumber
函数在数码管上显示不同数字,展示与时间相关信息。displayNumber
:根据传入数字从numCodes
数组获取段码,设置数码管引脚电平以显示相应数字。
总体而言,代码通过定时器中断控制,实现了基于 Arduino 的数码管和多个方向指示灯的协同工作,根据时间和状态变化展示不同信息。