今天学习的是数码管并复习了 LED 的封装代码。LED 的封装代码如下:
LED.h
- #ifndef __LED_H__
- #define __LED_H__
-
- #include "STC32G_Delay.h"
-
- #define LED_ON 0 // LED 灯打开的时候的值
- #define LED_OFF 1 // LED 灯关闭的时候的值
-
- /*!
- \brief 初始化 LED
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void led_init();
-
- /*!
- \brief 为所有灯设置高低电平
-
- \param[in] v[uint16] : 高电平(1), 低电平(0)
- \param[out] none
- \retval none
- */
- void set_all_led(uint16 v);
-
- /*!
- \brief 为指定索引的灯设置高低电平
-
- \param[in] index[uint16] : 索引值, 取值范围(0...7)
- \param[in] value[uint16] : 高电平(1), 低电平(0)
- \param[out] none
- \retval none
- */
- void set_led(uint16 index, uint16 value);
-
- /*!
- \brief 打开指定索引的灯
-
- \param[in] index[uint16] : 索引值, 取值范围(0...7)
- \param[out] none
- \retval none
- */
- void turn_on_led(uint16 index);
-
- /*!
- \brief 关闭指定索引的灯
-
- \param[in] index[uint16] : 索引值, 取值范围(0...7)
- \param[out] none
- \retval none
- */
- void turn_off_led(uint16 index);
-
- /*!
- \brief 打开所有灯
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void turn_on_all_led();
-
- /*!
- \brief 关闭所有灯
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void turn_off_all_led();
-
- /*!
- \brief LED 灯运行跑马灯或流水灯
-
- \param[in] status [u8] : 灯的状态, 0 或 1
- \param[in] start [u16]: 起始索引, 取值范围[0, 7]
- \param[in] step [u16]: 移动步长
- \param[in] flowing [u16]: 是否是流水灯, 1: 流水不灭, 0: 走马单亮
- \param[out] none
- \retval none
- */
- void led_run(u8 status, u16 start, int step, u16 flowing);
-
- /*!
- \brief SOS 灯
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void led_sos();
-
- #endif
复制代码
LED.c
- #include "LED.h"
-
- /*!
- \brief 初始化 LED
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void led_init() { P2M1 = 0x00, P2M0 = 0x00; }
-
- /*!
- \brief 为所有灯设置高低电平
-
- \param[in] v[uint16] : 高电平(1), 低电平(0)
- \param[out] none
- \retval none
- */
- void set_all_led(uint16 v) { P27 = P26 = P25 = P24 = P23 = P22 = P21 = P20 = v; };
-
- /*!
- \brief 为指定索引的灯设置高低电平
-
- \param[in] index[uint16] : 索引值, 取值范围(0...7)
- \param[in] value[uint16] : 高电平(1), 低电平(0)
- \param[out] 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 打开指定索引的灯
-
- \param[in] index[uint16] : 索引值, 取值范围(0...7)
- \param[out] none
- \retval none
- */
- void turn_on_led(uint16 index) { set_led(index, LED_ON); }
-
- /*!
- \brief 关闭指定索引的灯
-
- \param[in] index[uint16] : 索引值, 取值范围(0...7)
- \param[out] none
- \retval none
- */
- void turn_off_led(uint16 index) { set_led(index, LED_OFF); }
-
- /*!
- \brief 打开所有灯
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void turn_on_all_led() { set_all_led(LED_ON); }
-
- /*!
- \brief 关闭所有灯
-
- \param[in] none
- \param[out] none
- \retval none
- */
- void turn_off_all_led() { set_all_led(LED_OFF); }
-
- /*!
- \brief LED 灯运行跑马灯或流水灯
-
- \param[in] status [u8] : 灯的状态, 0 或 1
- \param[in] start [u16]: 起始索引, 取值范围[0, 7]
- \param[in] step [u16]: 移动步长
- \param[in] flowing [u16]: 是否是流水灯, 1: 流水不灭, 0: 走马单亮
- \param[out] 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 灯
-
- \param[in] none
- \param[out] 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"
-
- #define DI P15 // 数据输入 ( DI:P44)
- #define RCK P16 // 锁存寄存器(RCK:P43)
- #define SCK 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 拓展板 - 数码管内容显示
- \param[in] num : 显示的内容, 控制显示的什么内容, 支持八位十六进制表示的值
- \param[in] idx : 数码管的位置, 控制显示哪几个显示
- \param[out] 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[0]);
-
- while (1) {
- nixie_tube_show(LED_TABLE[index++], 0xFF); // 测试数码管
- if(index > length - 1) {
- index = 0;
- }
- P20 = !P20; // 每秒切换一次 LED 灯状态
- delay_ms(1000);
- }
- }
复制代码
小结:
虽然实现了点亮数码管的结果,但是还是存在根本性问题,那就是时间延迟的问题。我使用 STCAI-ISP 工具的软件延迟计算器生成的延迟函数,通过逻辑分析仪采集的结果并不是相匹配的时间。通过封装 LED 灯就能发现,使用库函数 STC32G_Delay.h 中的延迟函数效果也是不对的,所以我在怀疑是不是屠龙刀板子上没有晶振,但是我拿到的屠龙刀板子是缺少很多元件的。所以,就得不断调整 delay 函数中的数值,来匹配逻辑分析仪中接近期望值,从而实现相对符合期望的延迟效果。
附张效果图:
|