学习《Ai8051U教学视频》学习心得,送强大的 Ai8051U实验箱 | 已送
第一集-序言开篇说到,哪怕梦想让我们遍体鳞伤,这一次我们也要勇往直前,人总要有梦想,学习单片机也是一部分,刚开始学习单片机的时候总是遇到各种各样的问题,有时候是自己不小心输出指令,有时候又是因为逻辑问题,遇到这些问题的时候,不知道如何解决的时候,让我失去信心,不想去学单片机,但是梦想油让我坚持下去。但是有了国芯交流社区,让我能快速解决问题,并不断了解芯片功能,学习芯片的各种使用,也提供了各种芯片方便我们学习,所以这边要感谢国芯平台。好了感慨完了,开始进入正题。8051U相对于之前型号的国芯芯片强在哪里呢?一张图给了答案。1、屏幕显示和视频播放(flash编程器)这得益于8051U相比之前型号的国芯芯片有更强的RAM资源,性能不输ARM的32位芯片。2、2.IIS录放音,之前芯片无I2S功能这个新增的可以实现音频录制和播放。3、PWM_DMA,这个也是新增的实现更快更强大的功能。4、频谱分析仪(上位机),这个感觉介绍的不是很多,还有待自己学习下。5、手写计算器,看了介绍视频感觉蛮好玩的,但这些都需要AI计算。6、QSPI,PWM移相,硬件乘除,单精度浮点,QSPI可以实现更快速的SPI通信但必须硬件支持,其它那些更多更多运用在算法和运算上,感觉现在自己的实力还不是能很好的运用。
最后一张图是关于AI8051U的功能介绍,以及编译器的选择等。这些可以先了解以后在实际使用中,才会对芯片更有了解。
这节课就学习到这了。
第二课、硬件及工具介绍俗话说:工欲善其事,必先利其器,要学好一样东西必须先了解它的结构和功能,以及如何去使用它,所以这节课主要是去了解AI8051U的硬件结构和编译器的选择和使用以及程序的下载。首先看图了解AI8051U的硬件。
立体声线路输出立体声耳机输出话简录音示波器BNC输入OLED显示屏SPI/I2C8/7线接口TF卡插座USB转双串口USB-TypeCUSB Link 1D接口USB-TypeA8路流水灯RTC电池LCD对比度调节外部并行总线扩展32KSRAM(需自行焊接)8位数码管TFT彩屏QSPI/SPI FLASH电源按键(按下断电)复位按键红外接收红外发射矩阵键盘Ai8051UADC键盘TO、T1按键INTO、INT1按键掉电检测电压调节32768Hz无源晶振24C02 EEPROMDS18B20温度传感器TLV320AIC23B I2SDACLMV35874HC4051、TP2604STP2604SAI8H2K12U USB转双串口SP3485无源峰鸣器(这个应该是压电蜂鸣器吧)以上是AI8051U带的硬件部分。
了解硬件就开始软件部分,AI8051U可以使用keil C51 SDCC、IAR等51编译器,也可以使用keil C251编译器。这些因之前已经安装就不在多写了。
这些论坛已经有很多相关内容了,且我这边已经安装完成,就不重复了。
第三课\03.点亮第一个LED首先要打开一个LED灯就要有电势差,AI8051U的LED采用共阳模式,所以要让LED亮的前提是LED灯的电源导通和,GPIO为低,LED才会亮。知道怎么让LED亮了,但是IO也有模式控制不是上电就可以直接可以让IO控制也必须对IO进行配置,默认配置成准双向口就可以。IO默认输出高电平所以要把IO置零。
点亮一个LED程序如下。因为没用AI8051U开发箱就不上传了。
第五集、不断电下载
如果每次下载都要按下P32在按ON/OFF,很麻烦,有没有用办法不按任何按键就能下载固件呢?有那就是不断电下载了,
需要USB初始化函数,及lib文件程序需要使用XFR,所以要对P_SW2寄存器的第7位置1,P_SW2= 0x80;但是为了P_SW2有8位为了防止因为对第7位置1把0-6位置零所以使用或运算,所以变成P_SW2|= 0x80,因为使用不断电下载需要使用USB中断,故IE2对USB中断的控制和P_SW2一样,变成IE2|=0x80;由于开启了USB中断就需要使用所以要开启总中断EA=1;其它就是USB初始化及控制指令部分了。
代码如下#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void GPIO_Init()
{
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;
}
void main(void)
{
P_SW2 |= 0x80; //B7位写1,使能访问XFR
GPIO_Init();
usb_init(); //USB CDC 接口配置
P40 = 0; //P40端口输出0V
IE2 |= 0x80; //使能USB中断
EA = 1; //IE |= 0X80;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady)
{
USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done();
}
P00 = 0; //P00端口输出0V.打开P00的LED灯
}
}
第五课 C语言基础 关于C语言基础。这一讲开篇就开始讲解的是printf函数的定义及fmt格式控制字符串,但是我感觉在讲之前可以先说一下流程图,我个人感觉流程图虽然不是C语言的基础但是一开始就能把整个编程思路理清楚能让我们更快速的去开发程序。#define printfprintf_hidint printf_hid (const char *fmt, ...);这是print函数的原型的定义,参数fmt -- 是格式控制字符串,包含了两种类型的对象:普通字符和转换说明 。普通字符:在输出时,普通字符将原样不动地复制到标准输出。 printf("8051U深度入门到32位51大型实战视频\r\n"); 转换说明:不直接输出,用于控制 printf 中参数的转换和打印。每个转换说明都由一个百分号字符(%)开始,以转换说明符结束,从而说明输出数据的类型、宽度、精度等。 printf("8051U深度入门到32位51大型实战视频,%s\r\n","加油");转换说明简介:1.类型:根据不同的 fmt 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 fmt 参数中指定的每个 % 标签。关于附加参数,既可以是变量,也可以是常量。 2.位置:printf()函数的普通字符和转换说明放在" "双引号内,附加参数放在双引号外,每个附加参数之间用逗号隔开。 3.数量:printf() 的附加参数与转换说明符是⼀⼀对应关系,如果有 n 个转换说明符, printf() 的参数就应该有 n + 1 个。如果参数个数少于对应的转换说明符,printf() 可能会输出内存中的任意值。转换说明简介:1.类型:根据不同的 fmt 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 fmt 参数中指定的每个 % 标签。关于附加参数,既可以是变量,也可以是常量。 2.位置:printf()函数的普通字符和转换说明放在" "双引号内,附加参数放在双引号外,每个附加参数之间用逗号隔开。 3.数量:printf() 的附加参数与转换说明符是⼀⼀对应关系,如果有 n 个转换说明符, printf() 的参数就应该有 n + 1 个。如果参数个数少于对应的转换说明符,printf() 可能会输出内存中的任意值。printf("今天是%d年%d月%d日\r\n",24,11,16);这段直接使用C语言编译显示如下
1.转换说明符
%a(%A) 浮点数、十六进制数字和p-(P-)记数法(C99)
%c 字符
%d 有符号十进制整数
%f 浮点数(包括float和double)
%e(%E) 浮点数指数输出
%g(%G) 浮点数不显无意义的零"0"
%i 有符号十进制整数(与%d相同)
%u 无符号十进制整数
%o 八进制整数 e.g. 0123
%x(%X) 十六进制整数 e.g. 0x1234
%p 指针
%s 字符串
%% "%"2.标志
左对齐:"-" e.g. "%-20s"
右对齐:"+" e.g. "%+20s"
空格:若符号为正,则显示空格,负则显示"-" e.g. "% "
#:对c,s,d,u类无影响;对o类,在输出时加前缀o;对x类,在输出时加前缀0x;
对e,g,f 类当结果有小数时才给出小数点。3.格式字符串(格式)
[标志][输出最少宽度][.精度][长度]类型
"%-md" :左对齐,若m比实际少时,按实际输出。
"%m.ns":输出m位,取字符串(左起)n位,左补空格,当n>m or m省略时m=n
e.g. "%7.2s" 输入CHINA
输出" CH"
"%m.nf":输出浮点数,m为宽度,n为小数点右边数位
e.g. "%" 输入3852.99
输出3853.0
长度:为h短整形量,l为长整形量接下来就是ASCII了,正常我们显示的字都是ASCII字不是进制数。还有就是计算机采用的进制数了,有数的进制:2进制、10进制、16进制2进制转16进制一般是421模式的,16进制转2进制就是反过来算。C51数据的基本类型有:
bit,signed char,unsigned char,enum,signed short int,unsigned short int,signed int,unsigned int,
unsigned int,signed long int,float,double,idata*,data*,pdata*,near*,xdata*,code*,far*,huge*,
sbit,sfr,sfr16
如果想要使用64位的变量,需要在程序文件里面添加:#pragma float64
常用运算符:+、-、*、/
逻辑运算符:
&:逻辑与(and两个都为真结果为真)
|:逻辑或(or两个中任一个结果为真)
!:逻辑非(not真变假、假变真)
运算符:
==:判断运算符,判断两边数是否相等。=:赋值运算符,把右边的操作数赋给左边的操作数
+=:加且赋值运算符,把左边的操作数加上右边的操作数结果再赋给左边的操作数
-=:减且赋值运算符,把左边的操作数减去右边的操作数结果再赋给左边的操作数
*=:乘且赋值运算符,把左边的操作数乘右边的操作数结果再赋给左边的操作数
/=:除且赋值运算符,把左边的操作数除以右边的操作数结果再赋给左边的操作数
%=:求模且赋值运算符,把两个操作数的模运算结果赋给左边的操作数
<<=:左移且赋值运算符
>>=:右移且赋值运算符
&=:按位与且赋值运算符
^=:按位异或且赋值运算符
|=:按位或且赋值运算符
以下是示例程序#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#define u8unsigned char //8位无符号变量(0-255)
#define u16 unsigned int //16位无符号变量(0-65535)
u8 X = 10;
u8 Y = 10;
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void GPIO_Init()
{
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;
}
void main(void)
{
P_SW2 |= 0x80; //B7位写1,使能访问XFR
usb_init(); //USB CDC 接口配置
IE2 |= 0x80; //使能USB中断
EA = 1; //IE |= 0X80;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
//USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
if( X && Y ) //如果条件为真,输出什么
{
printf("条件为真\r\n");
}
else
{
printf("条件为假\r\n");
}
usb_OUT_done(); //
}
}
}
第六课:IO输出。
这几课讲了什么是GPIO,GPIO有什么功能,又是通过那个寄存器来控制GPIO的工作模式。并讲解了,这3种任务的实现。
任务1:按下P32按钮灯亮,松开P32按钮灯灭;
任务2:按下P32按钮灯灭,松开P32按钮灯亮;
任务3:按一下灯亮,按一下灯灭;
以及机械按键的抖动以及如何使用软件防抖的,接下来是课后小练:
按一下P32按钮灯亮,按一下P33按钮灯灭 代码如下:
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h" //d调用头文件
#define u8unsigned 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;
P40 = 0;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
//USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done(); //
}
按下P32按钮灯;
if( P32 == 0 ) P00 = 0;
//按下P33按钮灯;
if( P33 == 1 ) P00 = 1; //判断P33按钮是否按下
}按一下亮一颗灯,在按一下亮两颗灯,直到全亮(变量+加法和乘法)
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h" //d调用头文件
#define u8unsigned char //8位无符号变量(0-255)
#define u16 unsigned int //16位无符号变量(0-65535)
#define ON0
#define OFF 1
u8 state = 0; //初始状态
u8 code LEDState ={0xfd.0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00} //LED从P0从0开始亮到7全亮。
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;
P40 = 0;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
//USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done(); //
}
// //任务1:按下P32按钮灯亮,松开P32按钮灯灭;
// if( P32 == 0 ) //判断P32按钮是否按下
// {
// P00 = 0;
// }
// else
// {
// P00 = 1;
// }
//
// //任务2:按下P32按钮灯灭,松开P32按钮灯亮;
// if( P32 == 1 ) //判断P32按钮是否按下
// {
// P00 = 0;
// }
// else
// {
// P00 = 1;
// }
//任务3:按一下灯亮,按一下灯灭
if( P32 == 0 ) //判断P32按钮是否按下
{
Delay20ms(); //延时20ms消抖
if( P32 == 0 )
{
//state = !state; //变量取反 0 1 0 1 0 1
state++;
P0 = LEDState;
if(state==8) state=0;
while( P32 == 0 ); //等待P32松开
}
}
}
}
这个使用数组法。
第七集:讲解了定时器的使用和如何使用ISP软件生成定时时间,同时讲解了中断的使用,此处用定时器中断进行演示,定时器的优势是计时准确,且可以通过定时器,进行多任务操作。作业代码如下:#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h" //d调用头文件
#define u8unsigned char //8位无符号变量(0-255)
#define u16 unsigned int //16位无符号变量(0-65535)
u8 state = 0; //初始状态
u8 Run_State = 0; //运行状态
u8 gd_state = 0;
u8 count = 0;
u8 time = 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(!P32)
{
Delay20ms();
if(!P32)
{
key1_state=!key1_state;
if(gd_state==1)
{
printf("双倍功德时间");
count=count+2;
}
if(gd_state==0)
{
printf("单倍功德时间");
count=count+1;
}
while(!P32)
}
}
if(!P33)
{
Delay20ms();
if(!P33)
{
if(gd_state==1)
{
printf("功德+2当前功德:%d\r\n”,count);
}
if(gd_state==0)
{
printf("功德+1当前功德:%d\r\n”,count);
}
}
}
}
}
void Timer0_Init(void) //1秒@24.000MHz
{
TM0PS = 0x1E; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xFC; //设置定时初始值
TH0 = 0x03; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
void Timer0_Isr(void) interrupt 1 //1秒执行一次
{
time++;
if(gd_state==0&&time==1)
{
P00 = !state;
time=0;
}
if(gd_state==1&&time==2)
{
P00 = !state;
time=0;
}
}
<p>昨天已安排试验箱支持继续学习,请注意查收</p>
soma 发表于 2024-12-10 18:18
第七集:讲解了定时器的使用和如何使用ISP软件生成定时时间,同时讲解了中断的使用,此处用定时器中断进行 ...
好思维! 第8集 定时器周期性调度任务
这集讲定时器周期性调度任务,它使用了定时器,和数组和数据结构。
<div>
</div><div>typedef struct
{
u8 Run; //任务状态:Run/Stop
u16 TIMCount; //定时计数器
u16 TRITime; //重载计数器
void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;
</div>这是个数据结构通过typedef把名字替换成TASK_COMPONENTS,也就是说要调用这个数据结构的时候只要使用TASK_COMPONENTS就可以了。
这段static TASK_COMPONENTS Task_Comps[]把数据结构添加进数组Task_Comps里面,这样就可以把数据结构和数组复用了。
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 */
};void Task_Marks_Handler_Callback(void)这是回调函数作用是在定时器中断中对数据结构中TIMCount进行自减,通过ifTasks_Max对所有任务数都进行操作。
如果满足Task_Comps.TIMCount = Task_Comps.TRITime; 也就是计数和周期一致就开始执行任务。
void Task_Pro_Handler_Callback(void)这个函数放在main主函数的while里面让它一直在循环去执行任务。
其实定时时间不一定要1ms可以根据自己情况去调节,如果太短可能在复杂任务情况会对程序造成影响。
还有void (*TaskHook) (void)中定义任务的头文件一定要添加进调度程序里面否则会报错且程序不知道自己要执行什么。
页:
[1]
2