学习<Ai8051U教学视频>学习感悟 |已送实验箱
1.第一集讲了AI8051U的强大之处有1).屏幕显示和视频播放
2).IIS录放音
3).PWM_DMA
4).上位机频谱分析仪
5).手写计算器
6).QSPI,PWM硬件乘除,单精度浮点
是比之前的更加强大
第二课,
硬件介绍
SPI,IIC 数码管,流水灯, TFT屏幕, 掉电检测电压调节,无缘蜂鸣器,24c02 eeprom,ds18b20温度,32.78mhz无源晶振.
软件keil的安装介绍,添加stc的头文件,添加中断,下载工具用最新的ISP版本,有新功能,
下载时候8bit和32bit选择,代码是8位的就选8bit,否则就是32bit的。
对试验箱,模块和对应功能进行了介绍,对keil编译器,和下载工具使用方法做了介绍。 第三集,点亮一个LED灯
keil的小技巧扳手图标tab改为四个空格.
先介绍了工程的建立,
配置target下 :cpu mode 选择source251 4字节的中断模式选项要勾上。memory mode 下拉选Xsmall模式。 code mode size 下拉选large 64K的模式。 输出下面:hex文件在64k以内选择HEX-80,并勾上这个勾。
头文件在ISP工具里面找到头文件选择对应的AI-8051u的头文件,keil格式保存,
为什么能点亮LED灯,
IO就是GPIO分为四种模式:I就是input, O就是output ,0 0是准双向口:既能做输入也能做输出,0 1是推挽输出, 1 0是高阻输入 1 1是开路模式内部上拉电阻断开
如P0M0 = 0x00; P0M1 = 0x00;也就是配置P0为准双向口.
可以在ISP中配置IO模式并生成C代码。
语句结束要加分号,大括号要换行缩进
这节课讲了第一个最简单的代码,和它的原理。 第四集USB不停电下载
while里面走一圈就是一个循环。
为了代码稳定高效的运行一般采用查询的方式运行。
.lib文件添加方法和添加main.c文件的方法一样,并调用.lib文件的头文件。
用P_SW2寄存器打开扩展寄存器的功能。也就是打开USB可以访问的开关
IE2|= 0x80;打开USB中断的开关。
USB不停电下载
1实验对比演示
2.下载所需文件库函数,USB库文件。
3.移植关键部分到工程.
3.1添加头文件即.h文件
3.2.USB初始化函数,用.lib和.h文件实现
3.3命令参数.
3.4打开寄存器P_SW2和IE2寄存器
使用不停电下载程序的方法就是把不停电下载程序的代码复制到新的工程中 第五课 C语言基础
printf("X / Y = %u \n", (u16)(X / Y)); //u16强制类型转换 (X / Y)为变量,这里也可以放常量
printf("X %% Y = %u \n", (u16)(X % Y));
if ( X > Y)//如果条件为真输出什么
{
printf("条件为真\r\n");
}
else//else必须搭配if出现,不能单独出现else
{
printf("条件为假\r\n");
}
if ( X && Y)//如果条件为真输出什么
{
printf("条件为真\r\n");
}
else
{
printf("条件为假\r\n");
}
>><< 移位操作符,缺的位数补零
printf的格式控制符, 转义符,ASCII码表, 二进制、十进制、十六进制、每一个变量类型对应的数值长度。注意变量类型以及它的长度,数值一定不能溢出.
0为假,非0为真 第六课IO输入输出
变量取反
u8 state = 0;
//任务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 )
{
Delay20ms(); //延时20ms消抖
if (P32 == 0)
{
state = !state;
P00 = state; //变量取反0 1 0 1 0
printf("state: %d\r\n", (int)state);
while(P32 == 0); //等待P32松开
}
}
GPIO的介绍拉电流和灌电流,高低电平电压的介绍,按键原理和按键抖动的介绍
delay()函数是CPU停在这里不会往下走,这是一个很非内存的做法 第七节课定时器中断
void Timer0_Init(void) //3秒@24.000MHz
{
TM0PS = 0x5B; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x3F; //设置定时初始值
TH0 = 0x01; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
// TM0PS = 0x5B;91
//12T /12
// TH0 - TL0 = 319
}
void Timer0_Isr(void) interrupt 1 //3秒执行一次
{
state = !state;
P00 = state;
}
int count; //按键计数变量
if ( P32 == 0 )
{
Delay20ms(); //延时20ms消抖
if (P32 == 0)
{
printf("按键按下次数\xfd: %d\r\n", (int)count);
count++;
while(P32 == 0); //等待P32松开
}
}
定时频率(HZ) = Sysclk(hz)/((TM0PS + 1)*(65536-)*T)
定时时间(s) = ((TM0PS + 1)(65536-)*T)/Sysclk(hz)
= 65536-(Sysclk(hz) * 定时时间(s))/(T*(TM0PS + 1))
T = 1或者12.
16位自动重载定时器的本质就是从设定值数到65536(溢出)之后置位一次标志位,如果使能ET0就可以进入中断!
返回值类型 函数名(入口参数)
{
//函数体
//函数执行的代码
return 返回值;
}
函数的定义、声明、调用
定义:包含返回值,函数名和入口参数,并定义了函数 具体功能
函数的名称应当能够描述函数的功能,便于代码的阅读和理解.
函数名称应当使用有意义的英文单词或者组合的英文单词,避免使用特殊字符或数字。
函数名称不能与C语言的关键字同名。例如if等
返回值类型 函数名(入口参数);
声明: 在头文件或者被调用之前使用,注意末尾要加分号
函数名(入口参数);
调用:在需要调用的地方直接使用函数名,加上括号和分号。
如果有入口参数的,需要在括号的多个参数之间加逗号隔开。
int count; //按键计数变量
//任务2:灯按一下点亮三秒后熄灭
if ( P32 == 0 )
{
Delay20ms(); //延时20ms消抖
if (P32 == 0)
{
// printf("按键按下次数\xfd: %d\r\n", (int)count);
// count++;
P00 = 0;
Timer0_Init();
while(P32 == 0); //等待P32松开
}
}
void Timer0_Isr(void) interrupt 1 //3秒执行一次
{
// state = !state;
P00 = 1;
TR0 = 0; //定时器0关闭
}
void Timer0_Init(void) //500毫秒@24.000MHz
{
TM0PS = 0x0F; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xDC; //设置定时初始值
TH0 = 0x0B; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
int count; //按键计数变量
u8 state = 0; //初始状态
u8 Run_State = 0; //运行状态
//任务3:救护车灯控制器,按下报警按钮,红蓝灯交替闪烁(LED1和LED2表示红和蓝灯),再按一下报警按钮,红蓝灯停止。
if ( P32 == 0 )
{
Delay20ms(); //延时20ms消抖
if (P32 == 0)
{
Run_State = !Run_State; //运行状态取反
if ( Run_State == 1)
{
Timer0_Init();
}
else
{
TR0 = 0; //关闭定时器
P00 = 1;
P01 = 1;
}
// P00 = 0;
// Timer0_Init();
while(P32 == 0); //等待P32松开
}
}
void Timer0_Isr(void) interrupt 1 //500ms执行一次
{
state = !state;
P00 = state;
P01 = !state
}
定时器一次只能定时一次,如果我有很多个定时任务怎么办?
前后台的方法,用定时器做心跳2.5ms, 在中断中把HeartBeat = 1,,while(1) { if (HeartBeat) { HeartBeat = 0;}}根据定时任务的定时时间来执行,也就是说如果a任务是1s执行一次,if (count1S++>= 400)执行一次a任务count1S = 0;任务b是10s执行一次,if( count10S++ >= 4000) 执行一次任务b
第八节定时器周期性任务调度
ISP软件中
串口更多设置
数据分包显示
显示分包数据的收发时间
这节课的代码多,而且实现的任务比较多。
单片机型号错误 可以手动选择AI8051u-34K64, 或自动检测。
多任务,
任务调度系统,定时器驱动的所以时间会特别的准
周期性的多任务
手打实现三个任务,然后又讲了config.c config.h文件的固定格式,最后引入的任务调度系统,这个任务调度系统和前面三个任务实现的功能是基本一样的但是代码得到了精简和优化。这个任务调度系统模版更容易后期的维护,系统结构更加清晰,便于分层设计、利于系统抽象。
周期性任务介绍
任务1:用定时器实现这个任务。LED1实现0.3秒取反一次,LED2实现0.6秒取反一次,LED3 0.9秒取反一次
通过一个变量计数,假设这个变量1ms自加一次,加到300即为300ms加到600就是600ms,计数到达后从新清0
u8 State1 = 0; //LED1初始状态
u8 State2 = 0; //LED2初始状态
u8 State3 = 0; //LED3初始状态
u16 Count_ms = {0,0,0}; //三个计时变量
u8 State = {1,2,3,4,5,6,7,8,9,10};
u8 i;
//u16 Count_300 = 0; //计数300ms变量
//u16 Count_600 = 0; //计数600ms变量
//u16 Count_900 = 0; //计数900ms变量
void Timer0_Isr(void) interrupt 1 //1ms执行一次
{
// u8 i = 0;
for( i=0; i<3; i++)
{
Count_ms ++;
if( Count_ms >= 300)
{
Count_ms = 0;
State1 = !State1;
P00 = State1;
}
}
// Count_300++;
// Count_600++;
// Count_900++;
// state = !state;
// P00 = state;
// P01 = !state
}
int main()
{
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
for( i=0; i<3; i++)
{
printf("当前i的数\xfd值:%d\r\n", (int)i);
}
// printf("State的第一个数\xfd据为:%d\r\n", (int)State);
// State = 2;
// printf("从新修改后的State的第一个数\xfd据为: %d\r\n", (int)State);
usb_OUT_done();
}
// if (Count_300 >= 300 ) //300ms到达
// {
// Count_300 = 0;
// State1 = !State1; //LED1取反
// P00 = State1;
// }
// if (Count_600 >= 600 ) //600ms到达
// {
// Count_600 = 0;
// State2 = !State2; //LED2取反
// P01 = State2;
// }
// if (Count_900 >= 900 ) //900ms到达
// {
// Count_900 = 0;
// State3 = !State3; //LED3取反
// P02 = State3;
// }
}
}
//任务2:数组点亮LED,实现流水灯
注意事项:
LED是0点亮,1熄灭
数组长度需要把握好
流水灯移动的时间
注释办法/**/
/*
b0 b1 b7
低 高
LED0 - LED7
0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1
1 1 0 1 1 1 1 1
1 1 1 0 1 1 1 1
1 1 1 1 0 1 1 1
1 1 1 1 1 0 1 1
1 1 1 1 1 1 0 1
1 1 1 1 1 1 1 0
*/
u8 State = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
u8 num = 0;
int main()
{
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
//USB_SendData(UsbOutBufer, OutNumber); //发送数据缓冲区,长度(接收数据原样返回,用于测试)
usb_OUT_done();
}
if ( Count_ms >= 500 ) //500ms执行一次
{
Count_ms = 0;
P0 = ~State[ num ]; //num取值 0-7
num ++;
if ( num > 7) num = 0;
}
}
}
void Timer0_Isr(void) interrupt 1 //1ms执行一次
{
}
config.h
config.c
结构体数组的周期性任务调度
LED1 0.3秒闪一次, LED2 0.6秒闪一次, LED3 0.9秒闪一次
1都有定时器1ms加的变量
2又有一个设定的计数目标
3都有需要执行的功能;
4定时时间到了才能执行
typedef struct
{
u8 Run; //任务状态: Run/Stop
u16 TIMCount; //定时计数器
u16 TRITime; //重载计数器
void (*TaskHook)(void); //任务函数
} TASK_COMPONENTS;
static TASK_COMPONENTS Task_Comps[] =
{
//状态 计数 周期 函数
{0, 1, 1, 执行功能},
{0, 10, 10, 执行功能},
};
int main()
{
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
//USB_SendData(UsbOutBufer, OutNumber); //发送数据缓冲区,长度(接收数据原样返回,用于测试)
usb_OUT_done();
}
Task_Pro_Handler_Callback(); //执行功能函数
if ( Count_ms >= 500 ) //500ms执行一次
{
Count_ms = 0;
P0 = ~State[ num ]; //num取值 0-7
num ++;
if ( num > 7) num = 0;
}
}
}
void Timer0_Isr(void) interrupt 1 //1ms执行一次
{
Task_Marks_Handler_Callback(); //系统计时
}
视频持续更新中,等您拿到实验箱后,也期待分享更多测试成果和经验!加油! 加油
页:
[1]