[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 函数中的数值,来匹配逻辑分析仪中接近期望值,从而实现相对符合期望的延迟效果。
附张效果图:
这个是用595控制数码管吗 {:4_250:} soma 发表于 2024-6-5 09:02
这个是用595控制数码管吗
是的,因为数码管引脚太多,采用 74HC595 来控制数码管的话,只需要三个引脚就能控制数码管,很方便。
[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);
}
}
[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) { }
}
加油!!! 没板子可以学吗{:smile:}
页:
1
[2]