第九课 数码管 仿真接口
使用仿真接口的方法:
1. 打开 ISP 工具,打开菜单 “调试仿真接口” -- “接口设置”, 设置为“将所有调试接口绑定到 USB-CDC / 串口助手”
2. 打开 “CDC/HID-串口助手” , 选择串口与左侧的“扫描串口”选项一致(我这里是 com4 USB-CDC),然后“打开串口”
3. 再打开“调试仿真接口” - “擎天柱 - LED - DIP40” 。
在打开仿真接口时走了一些弯路。
1. 每个人的电脑打开的 com 口数量、序号是不同的。想我开发用的电脑, 实际使用的是 com4 ,并且只有一个。实际应用中,只要打开的com口与左侧使用的com口一致就行。(教学视频中有多个,让我以为可能存在多个)
2. 物理的 LED 灯,开启只要在 main 函数中打开 1 次就能点亮。 仿真接口的不可以, 我猜测是当main函数调用时, 仿真接口还没有就绪,因此做了个实验,在 main 函数中,放在 while(1) 循环之前,先 Delay(1000),再调用 PLED_40(), 就可以点亮了。这对初学者的我造成了一段时间的困惑,以为仿真接口没有正常工作。
代码片段
- void main(void)
- {
- sys_init();
- Timer0_Init();
-
- Init595();
-
- // 延迟 1 秒, 等待仿真接口加载完毕,再发送接口数据。
- Delay(1000);
- PLED_40();
-
- while(1)
- {}
复制代码
验证视频
源码
- #include "ai8051u.h" //调用头文件
- #include "stc32_stc8_usb.h" //调用头文件
- #include "stdlib.h"
-
- //注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,本节课程的其余内容(USB不停电下载)均通用!
- char* USER_DEVICEDESC = NULL;
- char* USER_PRODUCTDESC = NULL;
- char* USER_STCISPCMD = "@STCISP#";
-
- /* ----------------------------- config module ----------------------------- */
-
- void Timer0_Init(void); //1毫秒@24.000MHz
-
- void Delay(unsigned int ms); //@24.000MHz
-
- void sys_init(void); // 初始化
-
- void Timer0_Init(void) //1毫秒@24.000MHz
- {
- TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0xF0; //设置定时器模式
- TL0 = 0x30; //设置定时初始值
- TH0 = 0xF8; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0 = 1; //使能定时器0中断
- }
-
- void Delay(unsigned int ms) //@24.000MHz
- {
- unsigned char data i, j;
-
- while(ms--)
- {
- i = 24;
- j = 85;
- do
- {
- while(--j);
- }
- while(--i);
- }
- }
-
- void sys_init(void)
- {
-
- //P_SW2 |= 0x80; //B7位写1,使能访问XFR 等同于 EAFXR = 1;
- WTST = 0;
- EAXFR = 1;
- CKCON = 0;
-
- P0M1 = 0x00;
- P0M0 = 0x00;
- P1M1 = 0x00;
- P1M0 = 0x00;
- P2M1 = 0x00;
- P2M0 = 0x00;
- P3M1 = 0x00;
- P3M0 = 0x00;
- P4M1 = 0x00;
- P4M0 = 0x00;
- P5M1 = 0x00;
- P5M0 = 0x00;
- P6M1 = 0x00;
- P6M0 = 0x00;
- P7M1 = 0x00;
- P7M0 = 0x00;
-
- usb_init(); //USB CDC 接口配置
-
- IE2 |= 0x80; //使能USB中断
- EA = 1; //IE |= 0X80;
-
- while(DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
-
- }
-
- /* -----------------------------END config module END----------------------------- */
-
- /* ----------------------------- BEGIN button module BEGIN ----------------------------- */
-
- // 按钮状态
- typedef enum
- {
- KEY_STATE_IDLE,
- KEY_STATE_PRESS,
- KEY_STATE_CONFIRM,
- KEY_STATE_RELEASE
- } KeyState;
-
- // 按钮结构体
- typedef struct
- {
- unsigned char pin; // 按钮引脚电压 0 / 1
- KeyState state;
- unsigned int debounce_cnt;
- unsigned char press_flag;
- unsigned char change_flag;
- } KeyStruct;
-
-
- // 每毫秒扫描一次按钮状态变化
- // 找到遵循<抖动、按下、抖动、稳定>物理规律的按钮状态改变
- void KeyScan(KeyStruct* key, unsigned char current_pin);
-
- // 检查按键事件
- unsigned char Key_GetEvent(KeyStruct* key);
-
- // 每毫秒扫描一次按钮状态变化
- // 找到遵循<抖动、按下、抖动、稳定>物理规律的按钮状态改变
- void KeyScan(KeyStruct* key, unsigned char current_pin)
- {
- switch(key->state)
- {
- case KEY_STATE_IDLE:
- if(current_pin == 0) // 检测到按钮按下动作
- {
- key->state = KEY_STATE_PRESS;
- key->debounce_cnt = 0;
- }
- break;
- case KEY_STATE_PRESS:
- key->debounce_cnt++;
- if(key->debounce_cnt >= 20)
- {
- if(current_pin == 0) // 确实被按下,已停止抖动
- {
- key->state = KEY_STATE_CONFIRM;
- key->press_flag = 1;
- key->change_flag = 1;
- }
- else // 是抖动,按钮弹回原位
- {
- key->state = KEY_STATE_IDLE;
- }
- key->debounce_cnt = 0; // 不管是哪种情况, 消抖计数都归零
- }
- break;
- case KEY_STATE_CONFIRM:
- if(current_pin == 1) // 检测到按钮释放
- {
- key->state = KEY_STATE_RELEASE;
- key->debounce_cnt = 0;
- }
- break;
- case KEY_STATE_RELEASE:
- key->debounce_cnt++;
- if(key->debounce_cnt >= 20) // 20ms 释放消抖
- {
- if(current_pin == 1) // 确认按钮释放
- {
- key->state = KEY_STATE_IDLE;
- key->press_flag = 0;
- }
- else
- {
- key->state = KEY_STATE_CONFIRM; // 按钮弹回
- }
- key->debounce_cnt = 0;
- }
- break;
- }
- }
-
- // 检查按键事件
- unsigned char Key_GetEvent(KeyStruct* key)
- {
- if(key->change_flag)
- {
- key->change_flag = 0; // 有按键事件
- return 1;
- }
- return 0; // 无按键事件
- }
-
-
- /* ----------------------------- END button module END ----------------------------- */
-
- /* ----------------------------- BEGIN nixie module BEGIN ----------------------------- */
-
- // 定义 595 引脚
- #define HC595_SER P34
- #define HC595_RCK P35
- #define HC595_SCK P32
-
- // 10秒状态
- typedef enum
- {
- DS_STOP = 0,
- DS_RUN = 1,
- DS_CLEAN_STOP = 2,
- } DigitState;
-
- // 灯管模块
- typedef struct
- {
- unsigned int tms; // 灯管数值, 取值范围 0 - 9999
- DigitState state; // 灯光状态
-
- } LightModule;
-
- // 灯管模块
- LightModule digitLights = { 0, DS_STOP };
-
- void Init595(void);
- void Send595(unsigned char dat);
- void DisplaySeg(unsigned char segCode, unsigned char posCode);
-
- void targetLights(void);
- void DisplayDigitLights(void);
-
- // 段码
- unsigned char segNum[] =
- {
- 0x3F, /*'0', 0*/
- 0x06, /*'1', 1*/
- 0x5B, /*'2', 2*/
- 0x4F, /*'3', 3*/
- 0x66, /*'4', 4*/
- 0x6D, /*'5', 5*/
- 0x7D, /*'6', 6*/
- 0x07, /*'7', 7*/
- 0x7F, /*'8', 8*/
- 0x6F, /*'9', 9*/
- 0x77, /*'A', 10*/
- 0x7C, /*'B', 11*/
- 0x39, /*'C', 12*/
- 0x5E, /*'D', 13*/
- 0x79, /*'E', 14*/
- 0x71, /*'F', 15*/
- 0x40, /*'-', 16*/
- 0x00, /*' ', 17*/
- 0x80, /*'.', 18*/
- 0x78, /*'T', 19*/
- 0xBF, /*'0', 20*/
- 0x86, /*'1', 21*/
- 0xDB, /*'2', 22*/
- 0xCF, /*'3', 23*/
- 0xE6, /*'4', 24*/
- 0xED, /*'5', 25*/
- 0xFD, /*'6', 26*/
- 0x87, /*'7', 27*/
- 0xFF, /*'8', 28*/
- 0xEF, /*'9', 29*/
-
- };
-
- // 位码 0000 0001, 0000 0010, 0000 0100 ... 为方便赋值,使用了相反的二进制,使用时需要取反
- unsigned char posNum[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
-
- void Init595(void)
- {
- HC595_SER = 0;
- HC595_RCK = 0;
- HC595_SCK = 0;
- }
-
- void Send595(unsigned char dat)
- {
- unsigned char i;
- for(i=0; i < 8; i++)
- {
- dat <<= 1; // 左边1位移入 CY
- HC595_SER = CY;
- HC595_SCK = 1;
- HC595_SCK = 0;
- }
- }
-
- void DisplaySeg(unsigned char segCode, unsigned char posCode)
- {
- Send595(segCode);
- Send595(posCode);
- HC595_RCK = 1;
- HC595_RCK = 0;
- }
-
- // 挑战目标显示在数码管上
- void targetLights(void)
- {
- DisplaySeg(segNum[1], ~posNum[0]);
- Delay(1);
- DisplaySeg(segNum[20], ~posNum[1]);
- Delay(1);
- DisplaySeg(segNum[0], ~posNum[2]);
- Delay(1);
- DisplaySeg(segNum[0], ~posNum[3]);
- Delay(1);
- }
-
- // 10秒挑战 程序逻辑
- // 后面 4 位,默认静态显示 00.00
- // 按下 P32 按钮后,开始显示计时器,前面2位显示单位秒,后面两位分别显示百毫秒、十毫秒
- // 当计时器到达 99.99 秒后,计时器归零。
- // 在计时期间,按下 P32 按钮,可暂停计时,时间以1HZ的频率,闪烁显示按下时刻的值。
- // 当计时暂停时,按下 P32 按钮,计时器归零,并且停止闪烁。
- // 当再次按下 P32 按钮时,重新开始计时。
-
- void DisplayDigitLights(void)
- {
- unsigned char digit_1 = 0;
- unsigned char digit_2 = 0;
- unsigned char digit_3 = 0;
- unsigned char digit_4 = 0;
- digit_1 = digitLights.tms / 1000;
- digit_2 = (digitLights.tms % 1000) / 100;
- digit_3 = (digitLights.tms % 100) / 10;
- digit_4 = digitLights.tms % 10;
- DisplaySeg(segNum[digit_1], ~posNum[4]);
- Delay(1);
- DisplaySeg(segNum[digit_2 + 20], ~posNum[5]);
- Delay(1);
- DisplaySeg(segNum[digit_3], ~posNum[6]);
- Delay(1);
- DisplaySeg(segNum[digit_4], ~posNum[7]);
- Delay(1);
- }
-
- // 刷新灯管计时器
- void freshDigitLight(void)
- {
- switch((&digitLights)->state)
- {
- case DS_STOP: // 灯管处于准备状态
- if( (&digitLights)->tms > 0 )
- {
- (&digitLights)->tms = 0;
- }
- break;
- case DS_RUN: // 灯管处于运行状态, 计时器自增
- if( (&digitLights)->tms < 9999 )
- {
- (&digitLights)->tms++;
- }
- else
- {
- (&digitLights)->tms = 0;
- }
- break;
- case DS_CLEAN_STOP: // 灯管处于展示结果状态
- break;
- }
- }
-
- unsigned char idx = 0;
- unsigned char num[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
-
- void PLED_40(void)
- {
-
- BYTE cod[8];
- cod[0] = 0x0f;
- cod[1] = 0x00;
- cod[2] = 0x00;
- cod[3] = ~num[idx];
- cod[4] = 0xfe;
- LED40_SendData(cod, 5);
-
- P2 = ~num[idx];
-
- idx++;
- if(idx > 7)
- idx = 0;
-
- }
-
- /* ----------------------------- END nixie module END ----------------------------- */
-
-
- /* ----------------------------- BEGIN task module BEGIN ----------------------------- */
- // 任务对象
- typedef struct
- {
- unsigned char run_state; // 执行状态
- int timer; // 倒计时
- int cycle_length; // 执行周期
- void (*TaskHook)(void); // 任务回调函数
- } TASK_COMPONENT;
-
- void timer_callback(void);
- void task_callback(void);
-
- // 静态任务数组
- // 编译前已确定数组长度
- static TASK_COMPONENT tasks[] =
- {
- {0, 10, 10, freshDigitLight },
- {0, 500, 500, PLED_40 },
- };
-
- // 任务数组长度
- unsigned int tasks_length = sizeof(tasks) / sizeof(tasks[0]);
-
- // 定时器回调函数
- // 定时触发 run_state
- void timer_callback(void)
- {
- unsigned int i = 0;
- for(i = 0; i < tasks_length; i++)
- {
-
- if(tasks[i].timer == 0 && tasks[i].run_state == 0){
- tasks[i].timer = tasks[i].cycle_length;
- }
-
- if(tasks[i].timer > 0)
- {
- tasks[i].timer--;
- if(tasks[i].timer == 0)
- {
- tasks[i].timer = tasks[i].cycle_length;
- tasks[i].run_state = 1;
- }
- }
- }
- }
-
- // 任务处理回调函数
- // 定时执行任务
- void task_callback(void)
- {
-
- unsigned int i = 0;
- for(i = 0; i < tasks_length; i++)
- {
- if(tasks[i].run_state == 1)
- {
- tasks[i].run_state = 0;
- tasks[i].TaskHook();
- }
- }
-
- }
-
- /* ----------------------------- END task module END ----------------------------- */
-
- // 按钮
- KeyStruct key33 = {1, KEY_STATE_IDLE, 0, 0, 0};
-
- void main(void)
- {
- sys_init();
- Timer0_Init();
-
- Init595();
-
- while(1)
- {
-
- // PLED_40();
- // Delay(500);
-
- task_callback();
-
- // 如果按钮被按下
- // if(Key_GetEvent(&key33))
- // {
- // switch ( (&digitLights)->state )
- // {
- // case DS_STOP:
- // (&digitLights)->state = DS_RUN; // 开始计时
- // break;
- // case DS_RUN:
- // (&digitLights)->state = DS_CLEAN_STOP; // 停止计时
- // break;
- // case DS_CLEAN_STOP:
- // (&digitLights)->state = DS_STOP; // 清理计时结果
- // break;
- // }
- // }
-
- // 显示挑战目标 10.00 秒
- // targetLights();
-
- // 显示挑战结果,挑战前、挑战中、结果
- // DisplayDigitLights();
-
- if(bUsbOutReady)
- {
- //USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
-
- usb_OUT_done();
- }
-
- }
- }
-
- // 定时器中断回调函数
- void Timer0_Isr(void) interrupt 1
- {
- timer_callback();
- //KeyScan(&key33, P33);
- }
复制代码
|