使用国产仿真平台SmartEDA,进行Arduino仿真设计之简易红绿灯设计(一)

代码

// 定义第一个数码管引脚连接到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)

一、变量定义部分

  1. 引脚定义
    • 定义了两组数码管和两组指示灯的引脚连接到 Arduino 的引脚号。
    • const int segmentPins1[] 和 const int segmentPins2[] 分别定义了两个共阴极数码管(不包含小数点引脚)连接到 Arduino 的引脚数组。
    • const int ledPins1[] 和 const int ledPins2[] 分别定义了两个方向的三个灯(红、绿、黄)连接到 Arduino 的引脚数组。
  2. 数码管显示编码定义
    • const unsigned char numCodes[] 定义了数码管显示数字(1 - d)对应的段码(共阴极)。每个元素对应一个数字或字符的显示编码,通过二进制数来表示数码管各段的亮灭状态,以便后续在数码管上正确显示相应内容。
  3. 指示灯状态及时间相关变量定义
    • 针对两个方向的指示灯(这里假设为led_aled_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 等变量用于记录指示灯的亮灭状态(可能用于实现闪烁效果等)。

二、定时器中断服务函数

  1. 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 秒相关的操作,比如时间倒计时、状态切换等。

三、时间处理及状态更新函数

  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 的值,实现不同状态之间的转换,可能对应着指示灯不同的显示模式或行为。
  2. LedBTimeProcess函数
    • 与 LedATimeProcess 函数类似,针对 led_b 相关的时间和状态进行处理。先判断 led_b_time_s_flag 是否为 1,若是则进行相应的时间递减操作,并根据 led_b_status 的不同取值,通过 switch 语句实现不同状态之间的转换,以控制 led_b 相关的指示灯行为和时间倒计时效果。

四、指示灯刷新函数

  1. LedARefresh函数
    • 首先判断 led_a_time_shalf_flag 是否为 1,如果是,则将该标志位清零,并通过 led_a_light_status ^= 0x01 实现指示灯亮灭状态的切换(异或操作,每次执行都会改变当前亮灭状态)。
    • 然后根据 led_a_status 的不同取值,通过 switch 语句设置对应的 ledPins1 引脚的输出电平,从而控制第一个方向的三个指示灯(红、绿、黄)的亮灭状态,实现不同状态下指示灯的正确显示。
  2. LedBRefresh函数
    • 与 LedARefresh 函数类似,先判断 led_b_time_shalf_flag 是否为 1,进行相应的亮灭状态切换操作,然后根据 led_b_status 的不同取值,通过 switch 语句设置对应的 ledPins2 引脚的输出电平,控制第二个方向的三个指示灯的亮灭状态。

五、数码管刷新函数

  1. 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 相关的时间或其他信息。
  2. TubeBRefresh 函数
    • 与 TubeARefresh 函数类似,根据 led_b_status 的不同取值,通过 switch 语句调用 displayNumber 函数在第二个数码管上显示不同的数字,展示与 led_b 相关的时间或其他信息。

六、数码管显示相关函数

  1. displayNumber函数
    • 该函数用于在给定的数码管上显示给定的数字。
    • 首先判断传入的数字 number 是否在有效范围内(1 到 13 之间),如果是,则从 numCodes 数组中获取对应数字的段码 code
    • 然后通过循环遍历数码管的引脚数组 pins,使用 digitalWrite 函数根据段码中对应位的值(通过 bitRead 函数获取)设置每个引脚的输出电平,从而在数码管上正确显示出相应的数字。
  2. blink函数
    • 函数用于使数码管闪烁显示给定的数字。
    • 通过循环两次,每次先调用 displayNumber 函数显示数字,然后调用 clearDisplay 函数清除数码管显示(所有段熄灭),以此实现数码管的闪烁效果。这里原本可能有 delay 函数用于控制闪烁时间间隔,但代码中去掉了,可能是通过定时器中断来控制闪烁时间间隔。
  3. clearDisplay函数
    • 函数用于清除数码管显示(所有段熄灭)。
    • 通过循环遍历数码管的引脚数组 pins,使用 digitalWrite 函数将每个引脚的输出电平设置为 LOW,从而使数码管所有段熄灭。

七、初始化函数 setup

  1. 引脚模式初始化
    • 分别对两组数码管和两组指示灯的引脚进行初始化,将它们设置为输出模式。
    • 对于第一个数码管引脚数组 segmentPins1 的每个引脚,通过循环设置其引脚模式为 OUTPUT;同样对第一个方向的灯引脚数组 ledPins1、第二个数码管引脚数组 segmentPins2 和第二个方向的灯引脚数组 ledPins2 也进行了类似的初始化操作。
  2. 定时器 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)

八、主循环函数 loop

  1. 主循环操作
    • 在主循环 loop 中,依次调用了 LedATimeProcessLedBTimeProcessLedARefreshLedBRefreshTubeARefresh 和 TubeBRefresh 函数。
    • 通过不断循环执行这些函数,实现了对指示灯状态、时间的持续更新以及数码管显示内容的持续刷新,从而使整个系统能够根据设定的逻辑动态地展示相关信息和状态变化。

总体而言,这段代码实现了一个基于 Arduino 的系统,通过定时器中断来控制时间相关的操作,实现了两个方向的指示灯和两个数码管的协同工作,能够根据不同的状态和时间条件展示不同的信息,比如倒计时、状态切换以及相应的数码管显示等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值