nano 发表于 2024-6-4 20:53:40

[STC屠龙刀]学习打卡日历/学习感悟 - 第09集



今天学习的是数码管并复习了 LED 的封装代码。LED 的封装代码如下:


LED.h

#ifndef __LED_H__
#define __LED_H__

#include "STC32G_Delay.h"

#define LED_ON0// LED 灯打开的时候的值
#define LED_OFF 1// LED 灯关闭的时候的值

/*!
    \brief   初始化 LED
      
    \paramnone
    \param none
    \retval   none
*/
void led_init();

/*!
    \brief   为所有灯设置高低电平
      
    \paramv : 高电平(1), 低电平(0)
    \param none
    \retval   none
*/
void set_all_led(uint16 v);

/*!
    \brief   为指定索引的灯设置高低电平
      
    \paramindex : 索引值, 取值范围(0...7)
    \paramvalue : 高电平(1), 低电平(0)
    \param none
    \retval   none
*/
void set_led(uint16 index, uint16 value);

/*!
    \brief   打开指定索引的灯
      
    \paramindex : 索引值, 取值范围(0...7)
    \param none
    \retval   none
*/
void turn_on_led(uint16 index);

/*!
    \brief   关闭指定索引的灯
      
    \paramindex : 索引值, 取值范围(0...7)
    \param none
    \retval   none
*/
void turn_off_led(uint16 index);

/*!
    \brief   打开所有灯
      
    \paramnone
    \param none
    \retval   none
*/
void turn_on_all_led();

/*!
    \brief   关闭所有灯
      
    \paramnone
    \param none
    \retval   none
*/
void turn_off_all_led();

/*!
    \brief   LED 灯运行跑马灯或流水灯
      
    \paramstatus : 灯的状态, 0 或 1
    \paramstart   : 起始索引, 取值范围
    \paramstep    : 移动步长
    \paramflowing : 是否是流水灯, 1: 流水不灭, 0: 走马单亮
    \param none
    \retval   none
*/
void led_run(u8 status, u16 start, int step, u16 flowing);

/*!
    \brief   SOS 灯
      
    \paramnone
    \param none
    \retval   none
*/
void led_sos();

#endif


LED.c

#include "LED.h"

/*!
    \brief   初始化 LED
      
    \paramnone
    \param none
    \retval   none
*/
void led_init() { P2M1 = 0x00, P2M0 = 0x00; }

/*!
    \brief   为所有灯设置高低电平
      
    \paramv : 高电平(1), 低电平(0)
    \param none
    \retval   none
*/
void set_all_led(uint16 v){ P27 = P26 = P25 = P24 = P23 = P22 = P21 = P20 = v; };

/*!
    \brief   为指定索引的灯设置高低电平
      
    \paramindex : 索引值, 取值范围(0...7)
    \paramvalue : 高电平(1), 低电平(0)
    \param none
    \retval   none
*/
void set_led(uint16 index, uint16 value) {
      switch(index) {
                case 0: P20 = value; break; case 1: P21 = value; break;
                case 2: P22 = value; break; case 3: P23 = value; break;
                case 4: P24 = value; break; case 5: P25 = value; break;
                case 6: P26 = value; break; case 7: P27 = value; break;
      }
}

/*!
    \brief   打开指定索引的灯
      
    \paramindex : 索引值, 取值范围(0...7)
    \param none
    \retval   none
*/
void turn_on_led(uint16 index) { set_led(index, LED_ON); }

/*!
    \brief   关闭指定索引的灯
      
    \paramindex : 索引值, 取值范围(0...7)
    \param none
    \retval   none
*/
void turn_off_led(uint16 index) { set_led(index, LED_OFF); }

/*!
    \brief   打开所有灯
      
    \paramnone
    \param none
    \retval   none
*/
void turn_on_all_led() { set_all_led(LED_ON); }

/*!
    \brief   关闭所有灯
      
    \paramnone
    \param none
    \retval   none
*/
void turn_off_all_led() { set_all_led(LED_OFF); }

/*!
    \brief   LED 灯运行跑马灯或流水灯
      
    \paramstatus : 灯的状态, 0 或 1
    \paramstart   : 起始索引, 取值范围
    \paramstep    : 移动步长
    \paramflowing : 是否是流水灯, 1: 流水不灭, 0: 走马单亮
    \param none
    \retval   none
*/
void led_run(u8 status, u16 start, int step, u16 flowing) {
    u16 i = 0;
      status = status ? 1 : 0;
    for(i = start; i < 8 && i >= 0; i+= step) {
      set_led(i, status);
      delay_ms(10);
      if(!flowing) {
            turn_off_all_led();
      }
    }
}

/*!
    \brief   SOS 灯
      
    \paramnone
    \param none
    \retval   none
*/
void led_sos() {
      int i = 0;
      unsigned int times = 0;
      for(i = 0; i < 9; i++) {
                times = i < 3 || i > 5 ? 100 : 300;
                turn_on_all_led();
                delay_ms(times);
                turn_off_all_led();
                delay_ms(times);
      }
}


main.c

#include "stc_usb_auto_download.h"

// ==============================================================================================
// 数码管
//
// 外接拓展板引脚说明
// · 使用屠龙刀的 P15、P16 和 P17 外接拓展板来做实验
// · 拓展板的排针引脚 P44、P43 和 P42 分别连接数码管模块, 对饮模块的 DI、RCK 和 SCK
// · 所以需要通过杜邦线将 P15 连接 P44、P16 连接 P43、P17 连接 P42
// · 通过控制屠龙刀的 P15、P16 和 P17 的高低电平来实现数码管的数据显示
// ==============================================================================================

#include "LED.h"

#defineDI      P15 // 数据输入( DI:P44)
#defineRCK   P16 // 锁存寄存器(RCK:P43)
#defineSCK   P17 // 移位寄存器(SCK:P42)

static void delay_ms(unsigned int ms) {
      unsigned int i;
      do{
                i = MAIN_Fosc / 18000;
                while(--i);
      }while(--ms);
}

void delay_1us(void) {
      unsigned long edata i;

      _nop_();
      _nop_();
      _nop_();
      i = 598UL;
      while (i) i--;
}

static unsigned char LED_TABLE[] = {
      // 0         1         2      -> 9      (索引012...9)
      0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
      // 0.1. 2. -> 9.      (索引10,11,12....19)
    0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,
      // . -                                                (索引20,21)
      0x7F, 0xBF,
      // AbCdEFHJLPqU                (索引22,23,24....33)
      0x88,0x83,0xC6,0xA1,0x86,0x8E,0x89,0xF1,0xC7,0x8C,0x98,0xC1
};

void nixie_tube_input_data(unsigned char dat) {
      int i = 0;
    for (i = 7; i >= 0; i--) {
                // 数据输入
                DI = (u8)((dat & (1 << i)) >> i);
      // 移位
      SCK = 0; delay_1us(); SCK = 1; delay_1us();
    }
}

/*!
    \brief    拓展板 - 数码管内容显示
    \paramnum : 显示的内容, 控制显示的什么内容, 支持八位十六进制表示的值
    \paramidx : 数码管的位置, 控制显示哪几个显示
    \param none
    \retval   none
*/
void nixie_tube_show(unsigned char num, unsigned char idx) {
      nixie_tube_input_data(num); // 输入内容
      nixie_tube_input_data(idx); // 输入位置
      
      // 锁存
      RCK = 0; delay_1us(); RCK = 1; delay_1us();
}

int main() {
      u8 index = 0, length = 0;

      auto_usb_hid_download();         // 开启自动下载
      
      P2M0=0x00, P2M1=0x00;    // 将共阳灯   P20...7   引脚设置为双向
      P5M0 |=0x10, P5M1 &=0x10;    // 将蜂鸣器   P54         引脚设置为推挽
      P3M0 &= ~0x08, P3M1 &= ~0x08;    // 将按键的   P33         引脚设置为准双向
      P1M0 &= ~0xe0; P1M1 &= ~0xe0;    // 将数码管的 P15/P16/P17 引脚设置为准双向

      turn_on_all_led();               // 测试开灯
      delay_ms(5000);                  // 测试延迟 1s
      turn_off_all_led();            // 测试关灯
      
      length = sizeof(LED_TABLE) / sizeof(LED_TABLE);
      
    while (1) {
                nixie_tube_show(LED_TABLE, 0xFF); // 测试数码管
                if(index > length - 1) {
                        index = 0;
                }
                P20 = !P20;                              // 每秒切换一次 LED 灯状态
                delay_ms(1000);
      }
}


小结:

虽然实现了点亮数码管的结果,但是还是存在根本性问题,那就是时间延迟的问题。我使用 STCAI-ISP 工具的软件延迟计算器生成的延迟函数,通过逻辑分析仪采集的结果并不是相匹配的时间。通过封装 LED 灯就能发现,使用库函数 STC32G_Delay.h 中的延迟函数效果也是不对的,所以我在怀疑是不是屠龙刀板子上没有晶振,但是我拿到的屠龙刀板子是缺少很多元件的。所以,就得不断调整 delay 函数中的数值,来匹配逻辑分析仪中接近期望值,从而实现相对符合期望的延迟效果。

附张效果图:








soma 发表于 2024-6-5 09:02:21

这个是用595控制数码管吗

小涵子爸爸 发表于 2024-6-5 09:39:33

{:4_250:}

nano 发表于 2024-6-5 14:19:37

soma 发表于 2024-6-5 09:02
这个是用595控制数码管吗

是的,因为数码管引脚太多,采用 74HC595 来控制数码管的话,只需要三个引脚就能控制数码管,很方便。

nano 发表于 2024-6-5 21:38:57

[STC屠龙刀]学习打卡日历/学习感悟 - 第10集

本帖最后由 nano 于 2024-6-5 22:43 编辑



今天学习的依然是数码管,并完成了课后的作业。飞线太麻烦了。希望能早些得到实验箱。今日练习代码如下:


#include "stc_usb_auto_download.h"

// ==============================================================================================
// 数码管 + 蜂鸣器
//
// 做一个简易时钟,功能如下:
// 1.初始状态显示, 分别作为 时, 分, 秒
// 2.每隔一秒钟, 秒+1, 一分钟, 分+1, 以此类推
// 3.时间到达的时候,蜂鸣响3秒钟表示闹钟
//
// 外接拓展板引脚说明
// · 使用屠龙刀的 P15、P16 和 P17 外接拓展板来做实验
// · 拓展板的排针引脚 P44、P43 和 P42 分别连接 74HC595 模块 , 对应模块的 DI、RCK 和 SCK 引脚
// · 所以需要通过杜邦线将 P15 连接 P44、P16 连接 P43、P17 连接 P42
// · 通过控制屠龙刀的 P15、P16 和 P17 的高低电平来控制移位寄存器进而实现数码管的数据显示
// · 有源蜂鸣器模块连接屠龙刀的 P54 引脚, 低电平工作
// ==============================================================================================

#include "LED.h"

#defineDI      P15 // 数据输入( DI:P44)
#defineRCK   P16 // 锁存寄存器(RCK:P43)
#defineSCK   P17 // 移位寄存器(SCK:P42)
#define BIT(x)   (unsigned char)(0x01U << x)

static void delay_ms(unsigned int ms) {
        unsigned int i;
        do{
                i = MAIN_Fosc / 20000;
                while(--i);
        }while(--ms);
}

static void delay_1us(void) {
        _nop_();
        _nop_();
//        _nop_();
//        _nop_();
}

static unsigned char LED_TABLE[] = {
        // 0         1       2        -> 9        (索引012...9)
        0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
        // 0.1. 2. -> 9.        (索引10,11,12....19)
    0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,
        // . -                                                (索引20,21)
        0x7F, 0xBF,
        // AbCdEFHJLPqU                (索引22,23,24....33)
        0x88,0x83,0xC6,0xA1,0x86,0x8E,0x89,0xF1,0xC7,0x8C,0x98,0xC1
};

/*!
    \brief    拓展板 - 移位寄存器数据输入
    \paramdat : 需要输入的数据
    \param none
    \retval   none
*/
void nixie_tube_input_data(unsigned char dat) {
        char i = 0;
    for (i = 7; i >= 0; i--) {
                DI = (u8)((dat & (1 << i)) >> i);         // 数据输入
      SCK = 0; delay_1us(); SCK = 1; delay_1us(); // 移位
    }
}

/*!
    \brief    拓展板 - 数码管内容显示
    \paramnum : 显示的内容, 控制显示的什么内容, 支持八位十六进制表示的值
    \paramidx : 数码管的位置, 控制显示哪几个显示
    \param none
    \retval   none
*/
void nixie_tube_show(unsigned char num, unsigned char idx) {
        nixie_tube_input_data(num);                  // 输入内容
        nixie_tube_input_data(idx);                  // 输入位置
        RCK = 0; delay_1us(); RCK = 1; delay_1us();// 锁存
}

/*!
    \brief    拓展板 - 数码管显示时间
    \paramhour   : 小时数
    \paramminute : 分钟数
    \paramsecond : 秒钟数
    \param none
    \retval   none
*/
void nixie_tube_show_time(u16 hour, u16 minute, u16 second) {
        u8 i = 0;
       
        i = hour / 10;
        nixie_tube_show(LED_TABLE, BIT(0)); delay_ms(1);
        i = hour % 10;
        nixie_tube_show(LED_TABLE, BIT(1)); delay_ms(1);
       
        nixie_tube_show(0xBF, BIT(2));         delay_ms(1);
       
        i = minute / 10;
        nixie_tube_show(LED_TABLE, BIT(3)); delay_ms(1);
        i = minute % 10;
        nixie_tube_show(LED_TABLE, BIT(4)); delay_ms(1);
       
        nixie_tube_show(0xBF, BIT(5));         delay_ms(1);
       
        i = second / 10;
        nixie_tube_show(LED_TABLE, BIT(6)); delay_ms(1);
        i = second % 10;
        nixie_tube_show(LED_TABLE, BIT(7)); delay_ms(1);
       
}

int main() {
        u8 i = 0;
        u16 hour = 0, minute = 0, second = 0;
        auto_usb_hid_download();         // 开启自动下载
       
        P2M0=0x00, P2M1=0x00;    // 将共阳灯   P20...7   引脚设置为双向
        P5M0 |=0x10, P5M1 &=0x10;    // 将蜂鸣器   P54         引脚设置为推挽
        P3M0 &= ~0x08, P3M1 &= ~0x08;    // 将按键的   P33         引脚设置为准双向
        P1M0 &= ~0xe0, P1M1 &= ~0xe0;    // 将数码管的 P15/P16/P17 引脚设置为准双向
       
       
        P54 = 0;                         // 测试打开蜂鸣器
        delay_ms(300);                   // 测试延迟 1s
        P54 = 1;                         // 测试关闭蜂鸣器
        turn_on_all_led();               // 测试开灯
        delay_ms(5000);                  // 测试延迟 5s
        turn_off_all_led();            // 测试关灯
       
        // hour = 12, minute = 34, second = 0;
    while (1) {
                // 数码管显示时间
                nixie_tube_show_time(hour, minute, second);
                second++;
                if(second > 59) {
                        second = 0;
                        minute++;
                        if(minute > 59) {
                                minute = 0;
                                hour++;
                                if(hour > 23) {
                                        hour = 0;
                                }
                        }
                }
               
                // 时间到达的时候,蜂鸣响3秒钟表示闹钟
                if(hour == 0 && minute == 0) {
                        if(second >= 30 && second < 33) {
                                P54 = 0;
                        } else {
                                P54 = 1;
                        }
                }
               
                P20 = !P20;   // 每秒切换一次 LED 灯状态, 表示正常工作
                delay_ms(1000);
        }
}










nano 发表于 2024-6-6 21:32:08

[STC屠龙刀]学习打卡日历/学习感悟 - 第11集

本帖最后由 nano 于 2024-6-6 21:33 编辑



今天学习的是定时器,因为之前学习过 STC8H。所以,今天使用库函数来实现的定时器实验:


#include "stc_usb_auto_download.h"

// ==============================================================================================
// 定时器
// STC32G 系列单片机内部设置了 5 个 24 位定时器/计数器(8 位预分频+16 位计数)。
// 5 个 16 位定时器 T0、T1、T2、T3 和 T4 都具有计数方式和定时方式两种工作方式。
// ==============================================================================================

#include "STC32G_Timer.h"
#include "STC32G_GPIO.h"
#include "STC32G_NVIC.h"
#include "LED.h"

void Timer_config(void) {
      TIM_InitTypeDef                TIM_InitStructure;
      TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;      //指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
      TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;                  //指定时钟源,   TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
      TIM_InitStructure.TIM_ClkOut    = DISABLE;                              //是否输出高速脉冲, ENABLE或DISABLE
      
      TIM_InitStructure.TIM_Value   = (u16)(65536UL - (MAIN_Fosc / 10000UL));
      // 以上配置中, TIM_InitStructure.TIM_Value 最终会转化位寄存器配置。
      // 其中, 10000UL 表示的就是时钟周期, 意思就是这个 timer 回调1秒钟要调用 10000次计数。
      
      TIM_InitStructure.TIM_PS      = 0;                                        //8位预分频器(n+1), 0~255
      TIM_InitStructure.TIM_Run       = ENABLE;                              //是否初始化后启动定时器, ENABLE或DISABLE
      Timer_Inilize(Timer0,&TIM_InitStructure);                              //初始化Timer0          Timer0,Timer1,Timer2,Timer3,Timer4
      NVIC_Timer0_Init(ENABLE,Priority_0);                //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}

void Timer0_ISR_Handler (void) interrupt TMR0_VECTOR {
      P20 = ~P20;
}

int main() {
      auto_usb_hid_download();         // 开启自动下载
      
      Timer_config();
      led_init();

      turn_on_all_led();               // 测试开灯
      delay_ms(5000);                  // 测试延迟 5s
      turn_off_all_led();            // 测试关灯
      
    while (1) { }
}








阿杰爱学单片机 发表于 2024-7-24 10:53:31

加油!!!

阿杰爱学单片机 发表于 2024-7-24 11:01:38

没板子可以学吗{:smile:}
页: 1 [2]
查看完整版本: [STC屠龙刀]学习打卡日历/学习感悟 - 跟着冲哥学习 STC32G12K128