学习《8051U深度入门到32位51大型实战教学视频》
第一集学习本集,感受到了Ai8051u这个仿真实验板的强大功能!也感受到了新型高速单片机带来的极致体验效果。
希望在这里,通过国芯论坛,通过冲哥的视频教程,能学习到更好的硬件编程方法,和创造更有实用价值的制作。
哪怕梦想让我们拼的遍体鳞伤,这一次我们也要勇往直前!
谢谢冲哥送出的这勉励话语,我将让其陪伴左右,警醒自己!提升自己!
第二集介绍了AI8051U实验箱的各个硬件模块;编程软件、程序下载软件的下载与安装;简要介绍了软件的基本操作,如何添加头文件及如何加入扩展功能等的操作。
第三集
课程开始,冲哥就讲解了keil软件的启动和工程的建立!搭建了一个基本的软件代码框架。
介绍了 GPIO
就拿P00来说,P00有4中状态,
假如P0组的引脚只有两种状态,那么仅需要P0M0就够用了,P0M0是一个字节(8位),即二进制为 0000 0000,其中每一位标志一个引脚状态,如下:
0:表示“准双向口”
1:表示“推挽输出”
举例 P0M0为 0100 0000 则表示 P06 为 “推挽输出”,其他7个都是“准双向口”。
第4集 USB不停电下载
上代码
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void main(void)
{
P_SW2 |= 0x80; //B7位写1,使能访问XFR
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();
IE2 |= 0x80; //使能USB中断
EA = 1;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady)
{
USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done();
}
P40 = 0;
P00 = 0;
P02 = 0;
//P01 = 0;
}
}
第5集 C语言基础
本集让我重新温习了一遍C语言
老师讲解了 printf, 实现USB-CDC串口发送。
上代码
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#define u8 unsigned char // 8位无符号变量(0-255)
#define u16 unsigned int // 16位无符号变量(0-65535)
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void main(void)
{
P_SW2 |= 0x80; // B7位写1,使能访问XFR
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完成配置
while (1)
{
if (bUsbOutReady) // 如果接收到了数据
{
printf("Ai8051U真强大\r\n");
usb_OUT_done(); //
}
}
}
运行效果图
第6集 IO输入输出
首先讲解了 GPIO 的概念。1 高电平 0 低电平
GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。
高电平就是指接近于电源正极电压的电平;也叫逻辑“1”; VDD最大电压不能超过5.5V。上限溢出允许0.3v内.
单片机输出高电平就是输出VCC电压,输出低电平就是输出GND的电压。
四种模式:准双向口、推挽输出、高阻输出、开漏模式。 灌电流(电源到管脚串电阻尽量大于1K,不小于470欧)和拉电流(管脚到Gnd,推挽/强上拉)的讲解
单片机电压3.3V,施密特触发器,低电平不能高于0.99V,高电平不能低于1.18V。
通过按键来检测io状态
按键消抖。延时20ms
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h" //d调用头文件
// 注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,按键通用,本节课程的其余内容均通用!
#define u8 unsigned char // 8位无符号变量(0-255)
#define u16 unsigned int // 16位无符号变量(0-65535)
u8 state = 0; // 初始状态
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void Delay20ms(void) //@24.000MHzDelay20ms();
{
unsigned long edata i;
_nop_();
_nop_();
i = 119998UL;
while (i)
i--;
}
void main(void)
{
WTST = 0;// 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; // 扩展寄存器(XFR)访问使能
CKCON = 0; // 提高访问XRAM速度
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完成配置
while (1)
{
if (bUsbOutReady) // 如果接收到了数据
{
// USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done(); //
}
// //任务1:按下P32按钮灯亮,松开P32按钮灯灭;
// if( P32 == 0 ) //判断P32按钮是否按下
// {
// P20 = 0;
// }
// else
// {
// P20 = 1;
// }
//
// 任务2:按下P32按钮灯灭,松开P32按钮灯亮;
// if( P32 == 1 ) //判断P32按钮是否按下
// {
// P20 = 0;
// }
// else
// {
// P20 = 1;
// }
// 任务3:按一下灯亮,按一下灯灭
if (P32 == 0) // 判断P32按钮是否按下
{
Delay20ms(); // 延时20ms消抖
if (P32 == 0)
{
state = !state; // 变量取反 0 1 0 1 0 1
P20 = state;
printf("state:%d\r\n", (int)state);
while (P32 == 0)
; // 等待P32松开
}
}
}
}
第七集 定时器
本集开始讲解Ai8051U最重要的数字外设之一: 定时器。
Ai8051U 系列单片机内部设置了 6 个 24 位定时器/计数器(8 位预分频+16 位计数)。6 个 16 位定时器 T0、T1、T2、T3、T4 和 T11 都具有计数方式和定时方式两种工作方式。
上代码,用定时器实现了3个小任务:
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h" //d调用头文件
#define u8 unsigned char // 8位无符号变量(0-255)
#define u16 unsigned int // 16位无符号变量(0-65535)
u8 state = 0; // 初始状态
u8 Run_State = 0; // 运行状态
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void Delay20ms(void) //@24.000MHzDelay20ms();
{
unsigned long edata i;
_nop_();
_nop_();
i = 119998UL;
while (i)
i--;
}
void Timer0_Init(void); // 3秒@24.000MHz //函数声明
void main(void)
{
int count = 1; // 按键计数变量
WTST = 0;// 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; // 扩展寄存器(XFR)访问使能
CKCON = 0; // 提高访问XRAM速度
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中断
//Timer0_Init(); //定时器初始化
EA = 1; // IE |= 0X80;
P40 = 0;
while (DeviceState != DEVSTATE_CONFIGURED)
; // 等待USB完成配置
while (1)
{
if (bUsbOutReady) // 如果接收到了数据
{
usb_OUT_done(); //
}
// 任务1:
if (P32 == 0) // 判断P32按钮是否按下
{
Delay20ms(); // 延时20ms消抖
if (P32 == 0)
{
printf("按键按下次数\xfd:%d 次\r\n", (int)count);
count++;
while (P32 == 0)
; // 等待P32松开
}
}
// 任务2:灯按一下点亮三秒后熄灭。
if (P32 == 0) // 判断P32按钮是否按下
{
Delay20ms(); // 延时20ms消抖
if (P32 == 0)
{
printf("按键按下次数\xfd:%d 次\r\n", (int)count);
count++;
P00 = 0;
Timer0_Init();
while (P32 == 0)
; // 等待P32松开
}
}
// 任务3:救护车灯控制器,按下报警按钮,红蓝交替闪烁(LED1和LED2表示红和蓝灯),再按一下报警按钮,红蓝灯停止。
if (P32 == 0) // 判断P32按钮是否按下
{
Delay20ms(); // 延时20ms消抖
if (P32 == 0)
{
Run_State = !Run_State; // 运行状态取反
if (Run_State == 1) // 运行
{
Timer0_Init();
}
else
{
TR0 = 0; // 关闭定时器
P00 = 1;
P01 = 1;
}
while (P32 == 0)
; // 等待P32松开
}
}
}
}
void Timer0_Init(void) // 500毫秒@24.000MHz
{
TM0PS = 0x0F; // 设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; // 定时器时钟12T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0xDC; // 设置定时初始值
TH0 = 0x0B; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 使能定时器0中断
}
void Timer0_Isr(void) interrupt 1 // 3秒执行一次
{
state = !state;
P00 = state;
P01 = !state;
}
<h2>第八集 定时器周期性调度任务</h2>
<p>学完本集,主要有二点收获:</p>
<ol>
<li>代码的模块化管理</li>
<li>任务的合理分解</li>
</ol>
<p>随着功能的增加,代码量也直线上升,如何组织代码很关键,对以后的需求变化影响至关重要。</p>
<pre><code>main.c 主模块
└─user
├─io.c io功能
├─config.c 配置
└─task.c 任务
</code></pre>
<p>主模块就显得非常简洁明了</p>
<pre><code class="language-c">#include "config.h"
#include "task.h"
#include "io.h"
void main(void)
{
Sys_init(); // 系统初始化
usb_init(); // USB CDC 接口配置
IE2 |= 0x80; // 使能USB中断
Timer0_Init(); // 定时器初始化
EA = 1; // IE |= 0X80;
P40 = 0;
while (DeviceState != DEVSTATE_CONFIGURED)
; // 等待USB完成配置
while (1)
{
if (bUsbOutReady) // 如果接收到了数据
{
usb_OUT_done(); //
}
Task_Pro_Handler_Callback(); // 执行功能函数
}
}
</code></pre>
<p>具体任务分解到了任务模块中</p>
<pre><code class="language-c">#include "task.h"
#include "io.h"
static TASK_COMPONENTS Task_Comps[] = {
// 状态计数周期函数
{0, 300, 300, LED0_Blink}, /* task 1 Period: 300ms */
{0, 600, 600, LED1_Blink}, /* task 1 Period: 600ms */
{0, 900, 900, LED2_Blink}, /* task 1 Period: 600ms */
{0, 10, 10, KEY_Task}, /* task 1 Period: 600ms */
};
u8 Tasks_Max = sizeof(Task_Comps) / sizeof(Task_Comps);
//========================================================================
// 函数: Task_Handler_Callback
// 描述: 任务标记回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2012-10-22
//========================================================================
void Task_Marks_Handler_Callback(void)
{
u8 i;
for (i = 0; i < Tasks_Max; i++)
{
if (Task_Comps.TIMCount) /* If the time is not 0 */
{
Task_Comps.TIMCount--; /* Time counter decrement */
if (Task_Comps.TIMCount == 0) /* If time arrives */
{
/*Resume the timer value and try again */
Task_Comps.TIMCount = Task_Comps.TRITime;
Task_Comps.Run = 1; /* The task can be run */
}
}
}
}
//========================================================================
// 函数: Task_Pro_Handler_Callback
// 描述: 任务处理回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2012-10-22
//========================================================================
void Task_Pro_Handler_Callback(void)
{
u8 i;
for (i = 0; i < Tasks_Max; i++)
{
if (Task_Comps.Run) /* If task can be run */
{
Task_Comps.Run = 0; /* Flag clear 0 */
Task_Comps.TaskHook(); /* Run task */
}
}
}
</code></pre>
<h2>第九集 数码管</h2>
<p>LED数码管由8个发光二极管构成,通过不同的组合可用来显示数字0~9、字符A~F和小数点“.”。分为共阳极和共阴极两种结构。</p>
<p>AIapp-ISP 工具提供了虚拟显示功能,极大地方便了开发调试。</p>
<p><img src="data/attachment/forum/202502/03/152202yw3baurdwuu3trbg.png" alt="1.PNG" title="1.PNG" /></p>
<p><img src="data/attachment/forum/202502/03/152240ln585k65n1n8nuoe.png" alt="image.png" title="image.png" /></p>
<p>代码</p>
<pre><code class="language-C">u8 SEG_NUM[] =
{
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*/
};
void SEG_PC(void)
{
u8 cod;
cod = SEG_NUM; // 小时的十位数的数码管段码
cod = SEG_NUM;
cod = SEG_NUM; // 数码管刷段码和位码
cod = SEG_NUM; // 分钟
cod = SEG_NUM;
cod = SEG_NUM; // 数码管刷段码和位码
cod = SEG_NUM; // 分钟
cod = SEG_NUM;
SEG7_ShowCode(cod);
}
</code></pre>
<h2><a href="https://www.stcaimcu.com/forum.php?mod=attachment&aid=NzY0ODV8Njc0NzZmZTF8MTczODU2MTg2M3wzNjc4NHwxMTkwMg%3D%3D">第十集 虚拟LED数码管</a></h2>
<p>准备好三件套</p>
<p><img src="data/attachment/forum/202502/03/165241avq2i76c7a6lia3a.png" alt="图片1.png" title="图片1.png" /></p>
<p>isp提供的虚拟功能为快速调试提供了便利条件。</p>
<ol>
<li>虚拟显示——LED</li>
</ol>
<p><img src="data/attachment/forum/202502/03/165241lydf1oqv7v0vo7b7.png" alt="11.PNG" title="11.PNG" /></p>
<p>2 虚拟显示——数码管</p>
<p><img src="data/attachment/forum/202502/03/165241g4rykx8k48rx4u4y.png" alt="22.PNG" title="22.PNG" /></p>
<p>3 虚拟键盘</p>
<p><img src="data/attachment/forum/202502/03/165241kj7z9aiol7jz8a7j.png" alt="33.PNG" title="33.PNG" /></p>
页:
[1]