找回密码
 立即注册
楼主: 电子DIY小家

《8051U深度入门到32位51大型实战视频》,【免费 + 包邮 送】实验箱@Ai8051U,100万套

   火... [复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-04-29 10:00:29
已绑定手机

12

主题

29

回帖

204

积分

中级会员

积分
204
发表于 2024-12-21 13:54:38 | 显示全部楼层

周期性多任务,讲的不错!shengli 有点理解了。多发点视让大家学习学习。祝愿国产单片机越做越好!

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:339
  • 最近打卡:2025-05-04 07:56:57

19

主题

205

回帖

824

积分

高级会员

积分
824
发表于 2024-12-21 14:03:15 | 显示全部楼层
macr*** 发表于 2024-12-16 04:26
第七集 定时器中断
了解了定时器的执行过程
配置定时器:设置定时器的工作模式、初值、是否启用中断等。

好思路。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:17
  • 最近打卡:2025-02-21 09:49:08
已绑定手机

4

主题

18

回帖

138

积分

注册会员

积分
138
发表于 2024-12-21 21:29:31 | 显示全部楼层
第九集和第十集是还没有发资料吗?

点评

发了哈~  详情 回复 发表于 2024-12-25 10:09
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:151
  • 最近打卡:2025-05-03 23:19:40

0

主题

10

回帖

546

积分

高级会员

积分
546
发表于 2024-12-21 22:40:54 | 显示全部楼层

打卡第四集,继续努力学习。。。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-05-04 00:21:51
已绑定手机

0

主题

36

回帖

512

积分

高级会员

积分
512
发表于 2024-12-22 07:18:55 | 显示全部楼层
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:13
  • 最近打卡:2025-05-01 11:26:42
已绑定手机

9

主题

14

回帖

172

积分

注册会员

积分
172
发表于 2024-12-22 12:02:09 | 显示全部楼层
# 第一集新建工程相关
- 51的新建工程需要注意Memory model,一般选择XSmall即可,tiny模式串口无法正常工作,原理至今还不是很清楚。
- 因为新建的工程默认为tiny模式,修改到XSmall即可。
![image.png](data/attachment/forum/202412/22/114726qlswlzw2idwfkpsv.png "image.png")

- 然后添加c文件到项目中就可以快乐的写代码了。
- AI8051 IO单独操作的方法,
- PnM1&=~0x20;给P15设置为推挽输出。P1M1的第五位置为0 
- PnM0|=0x20;//P1M0的第五位置为1
```c 
#include"AI8051U.h"
#include"intrins.h"//一定要加这两个头文件
typedef unsigned char u8;
typedef unsigned short int u16;
void delay_us(u16 us)
{
	do
	{
		NOP36();
	}
	while(us--);//us--需要先对us进行减一次,然后赋值给us,然后判断一次,一共需要4个指令周期,NOP36是36个指令周期,40*25=1000ns=1us
    //MOV R6,R7 //1个指令周期
    //DEC R7,#0X01//1个指令周期
    //CJNE R6,#0X00,C:0X0005//如果发生跳转,就是3个指令周期,正常情况为2个指令周期。
}
void delay_ms(u16 ms)	//unsigned int 
{
	do
	{
		delay_us(1000);//减少对函数的调用,增加性能
	}while(--ms);
}
void main()
{
	P0M0=0XFF;
	P0M1=0X00;//设置P0的IO为推挽输出
		while(1)
		{
			P00=1;//设置P00口为高电平
			delay_ms(500);
			P00=0;
			delay_ms(500);//设置P00口为低电平
		}
}

第二集 不停电烧录

  • 使用手册中的电路可以进行不停电烧录,挺方便的。
    image-1.png
  • 打开AIapp-ISP-v6.xx.exe软件,选择你需要烧录的hex文件,如果没有的话,去keil的魔法棒(options for target)中的output那一栏,勾选Create HEX file,点击OK,关闭这个(options for target)之后编译一下即可。hex文件一般在工程文件所在的目录下,找Objects。一般来说,默认的hex创建路径就在这个目录下。
  • 然后直接下载编程即可。

第三集 点亮rgb灯

  • 先上代码,
  • 基本上就是根据ws2812b的手册,确定发送数据的高低电平的长度就行。
#include "AI8051U.h"
#include "intrins.h"
 
typedef unsigned char u8;
typedef unsigned short int u16;

// 延时1us的时间为1000ns/25ns=40;
//  1/Fosc=x ns
//  1000ns/(1/Fosc)ns= x 个时钟周期
//  实际计算时:1000e-9*Fosc=x 个时钟周期
//  while(i--)四个时钟周期,(x-4)=NOP(val);延时1us所需要的时间
//这个代码使用的是IO口高低电平进数据发送。
u8 LED1[3]; // 红色(R=255, G=0, B=0)
u8 LED2[3]; // 绿色(R=0, G=255, B=0)
u8 color_table[5][3] = {
    {0xFF, 0x00, 0x00}, // 红色
    {0x00, 0xFF, 0x00}, // 绿色
    {0x00, 0x00, 0xFF}, // 蓝色
    {0xFF, 0xFF, 0x00}, // 黄色
    {0xFF, 0x00, 0xFF}  // 紫色
};
#define LED_PIN P15
// 该延时函数仅在40Mhz下是准确的,其他频率需要自行计算NOPx()的值
void delay_us(u16 us)
{
    do
    {
        NOP(36);
    } while (us--); // us--需要先对us进行减一次,然后赋值给us,然后判断一次,一共需要4个指令周期,NOP36是36个指令周期,40*25=1000ns=1us
    // MOV R6,R7 //1个指令周期
    // DEC R7,#0X01//1个指令周期
    // CJNE R6,#0X00,C:0X0005//如果发生跳转,就是3个指令周期,正常情况为2个指令周期。
    // 方案2
    // NOP40();
}
void delay_ms(u16 ms) // unsigned int
{
    do
    {
        delay_us(1000); // 减少对函数的调用,增加性能
    } while (--ms);
}
void send_byte(unsigned char byte)
{
    unsigned char i;
    for (i = 0; i < 8; i++)
    {
        if (byte & 0x80)
        {                // 如果最高位为 1
            LED_PIN = 1; // 发1 低电平为0.3us
            delay_us(1); //
            LED_PIN = 0;
            NOP13();
        }
        else
        {                // 如果最高位为 0
            LED_PIN = 1; // 发0 高电平为0.3us
            NOP13();     //
            LED_PIN = 0; //
            delay_us(1);
        }
        byte <<= 1; // 左移 1 位,准备发送下一位
    }
}

void switch_to_next_color(u8 *LED, u8 index)
{
    unsigned char i;
    LED[0] = color_table[index][0]; // G
    LED[1] = color_table[index][1]; // R
    LED[2] = color_table[index][2]; // B

    for (i = 0; i < 3; i++)
    {
        send_byte(LED[i]); // 发送每个颜色字节(G, R, B)
    }
}

void ws2812b_reset()
{
    LED_PIN = 0;
    delay_us(300); // 拉低时间大于 50 微秒即可
}
// 主程序
void main()
{

    u8 index1 = 0; // LED1 的颜色索引
    u8 index2 = 2; // LED2 的颜色索引

	P_SW2 = 0X80;
    CKCON = 0x00;
    WTST = 0x00;
    P4M0 = 0X00;
    P4M1 = 0X00;
    P1M0 |= 0x20;//设置P15为数据输出口
    P1M1 &= ~0x20;
    while (1)
    {
        ws2812b_reset();
        switch_to_next_color(LED1, index1);
        switch_to_next_color(LED2, index2);
        index1 = (index1 + 1) % 5; // 颜色表循环
        index2 = (index2 + 1) % 5; // 颜色表循环
        // 延时 5 毫秒,避免过快发送
        delay_ms(500);
    }
}
- 效果图

![IMG_20241222_1120511.jpg](data/attachment/forum/202412/22/115343m21a668fk6cm8k7j.jpg "IMG_20241222_112051[1].jpg")

第四集 串口使用

#include "AI8051U.h"
#include "intrins.h"
#include "stdio.h"
#define FOSC 40000000UL
#define BRT (65536 - (FOSC / 115200 + 2) / 4)
char buffer[16];
bit busy;
char wptr;
char rptr;
typedef unsigned char u8;
typedef unsigned int u16;
void delay_ms(u16 ms) // unsigned int
{
    u16 i = 0;
    do
    {
        for(i=0;i<900;++i)//11059200 243即可,40M i=900即可
        NOP40(); // 减少对函数的调用,增加性能
    } while (--ms);
}
void Uart2Isr() interrupt 8
{
    if (S2TI)
    {
        S2TI = 0;
        busy = 0;
    }
    if (S2RI)
    {
        S2RI = 0;
        buffer[wptr++] = S2BUF;
        wptr &= 0x0f;
    }
}
void Uart2Init()
{
    P_SW2 = 0x80;
    S2CFG = 0x01;
    S2CON = 0x50;
    T2L = BRT;
    T2H = BRT >> 8;
    T2x12 = 1;
    T2R = 1;
    wptr = 0x00;
    rptr = 0x00;
    busy = 0;
        P1M0&=~0X0C;
		P1M1&=~0X0C;
    IE2 = 0x01;
    EA = 1;
}
void Uart2Send(char dat)
{
    while (busy)
        ;
    busy = 1;
    S2BUF = dat;
}
void Uart2SendStr(char *p)
{
    while (*p)
    {
        Uart2Send(*p++);
    }
}
char putchar(char c)
{
	Uart2Send(c);
	return c;
}
// 主程序
void main()
{
	u16 index=0;
    P_SW2 = 0X80;
    CKCON = 0x00;
    WTST = 0x00;
    Uart2Init();
    Uart2SendStr("Uart Test !\r\n");
		printf("%d\n",index);
    while (1)
    {

			for(index=0;index<10;++index)
			{
				printf("Uart Test index=%d!\r\n",index);
        		delay_ms(1000);
			}
  
    }
}
- 主要的重点在于使用printf函数进行串口输出打印。加一个stdio.h的头文件,然后重定义一下putchar函数。
char putchar(char c)
{
	Uart2Send(c);
	return c;
}

![image-2.png](data/attachment/forum/202412/22/114917yldlkwxot9kdizk3.png "image-2.png")

第五集 按键使用

  1. 按键io初始化
void GPIO_init()
{
	P_SW2 = 0X80;
    CKCON = 0X00;
    WTST = 0X00;
    P2M0 = 0X00;
    P2M1 = 0X00;
    P1M0 &= ~0x10;//设置P14为双向口
    P1M1 &= ~0x10;
    P5M0 &= ~0x0c;//设置P52,P53为双向口
    P5M1 &= ~0x0c;
    P4M0 = 0X00;//设置P4为双向口
    P4M1 = 0X00;
    P1IM0 &=~0X10;//设置P14为下降沿中断
    P1IM1 &=~0X10;
    P1INTE|= 0x10;
    P5IM0 &=~0x0c;//设置P52 P53为下降沿中断
    P5IM1 &=~0x0c;//
    P5INTE|= 0x0c;//使能P52 P53中断
    P1INTE|= 0x10;
}
  1. 中断执行
void common_isr() interrupt 13
{
unsigned char intf;
unsigned char intf_5;
intf = P1INTF;
intf_5 = P5INTF;
  
    if(intf&0x10)//使用char型临时变量判断中断是否到来。
    {
        flag_ = 1;
    }
    if(intf_5&0x08)
    {
        flag_ = 3;

    }
    if(intf_5&0x04)
    {
        flag_ = 2;
    }
    P1INTF&=~0X10;//清除中断标志位
    P5INTF&=~0X0c;
}

把下面的代码。新建一个文件isr.asm,添加到项目中。由于中断向量大于31,借用13号中断地址入口。

CSEG AT 0133H
JMP P1INT_ISR
P1INT_ISR:
JMP 006BH
CSEG AT 0153H
JMP P5INT_ISR
P5INT_ISR:
JMP 006BH
END

第六集 多文件编译

  • 全局变量一定定义在头文件下面,函数声明和定义的前面
  • 函数在单独的C文件中需要有定义,在头文件中声明。需要调用这个函数的文件夹,需要extern 该函数的声明。
  • 具体demo见附件

第七集 pwm使用

  • 这个代码实现的功能为在PWMA的P00 和P01输出一个互补带死区的PWM波。用于驱动电机。
#include "AI8051U.H"
#include "intrins.h"

int main(void)

{
	P_SW2 = 0X80;
	CKCON = 0x00;
	WTST = 0x00;
	P0M1 = 0x00;
	P0M0 = 0xFF;
	P1M1&=~0x80;
	P1M0|=0x80;

	PWMA_ENO = 0xFF;
	PWMA_PS = 0x01;
	PWMA_PSCRH = 0x00;//预分频寄存器
	PWMA_PSCRL = 0x00;
	PWMA_DTR = 0x10;
 	PWMA_CCMR1 = 0x68;
	PWMA_CCMR2 = 0x68;
	PWMA_CCMR3 = 0x68;
	PWMA_CCMR4 = 0x68;
	PWMA_ARRH = 0x08;
	PWMA_ARRL = 0x00;
	PWMA_CCR1H = 0x04;
PWMA_CCR1L = 0x00;
PWMA_CCR2H = 0x02;
PWMA_CCR2L = 0x00;
PWMA_CCR3H = 0x01;
PWMA_CCR3L = 0x00;
PWMA_CCR4H = 0x01;
PWMA_CCR4L = 0x00;

PWMA_CCER1 = 0x55;
PWMA_CCER2 = 0x55;
//配置通道输出使能和极性
//配置通道输出使能和极性
PWMA_BKR = 0x80;
PWMA_IER = 0x02;
PWMA_CR1 = 0x01;
EA = 1;
P17=1;
while (1);
}
void PWMA_ISR() interrupt 26
{
if(PWMA_SR1 & 0X02)
{
P03 = ~P03;
PWMA_SR1 &=~0X02;
}
}

wx_camera_17345370721871.jpg

补充说明

时钟周期、机器周期、指令周期

机器周期、时钟周期和指令周期是8051单片机中的重要概念。

  • 时钟周期:单片机时钟信号的一个完整周期,即时钟源的周期,通常由晶振频率决定。
  • 机器周期:单片机执行基本操作所需的时间,通常由时钟周期数来决定。例如8051的一个机器周期为12个时钟周期。AI8051是单时钟/机器周期(1T)的单片机
  • 指令周期:执行一条指令的时间,通常由多个机器周期组成。
    由于AI8051为单时钟机器周期的单片机,所以其执行一条指令的时间为一个时钟周期。
    在40MHz的时钟下,时钟周期为1/40,000,000 = 25ns,因此一个机器周期为25ns。
  • 延时1us:1us = 1000ns,因此需要延时1000ns / 25ns =40;
  • 延时1ms:1ms = 1,000,000ns,延时1000000ns / 25ns = 40000。
    所以ai8051的较为精确的延时函数计算公式为

1/Fosc=x ns
1000ns/(1/Fosc)ns= x 个时钟周期
实际计算时:1000e-9*Fosc=x 个时钟周期
while(i--)四个时钟周期,(x-4)=NOP(val);延时1us所需要的时间

可以通过以下代码实现延时:
while(--us)

MOV R6,R7 //一个指令周期
DEC R7,#0X01//一个指令周期
CJNE R6,#0X00,C:0X0005//如果发生跳转,就是3个指令周期,正常情况为2个指令周期。

alt text

void delay_us(u16 us)
{
	do
	{
		NOP36();
	}
	while(us--);//us--需要先对us进行减一次,然后赋值给us,然后判断一次,一共需要4个指令周期,NOP36是36个指令周期,40*25=1000ns=1us
    //MOV R6,R7 //1个指令周期
    //DEC R7,#0X01//1个指令周期
    //CJNE R6,#0X00,C:0X0005//如果发生跳转,就是3个指令周期,正常情况为2个指令周期。
}
void delay_ms(u16 ms)	//unsigned int 
{
	do
	{
		delay_us(1000);//减少对函数的调用,增加性能
	}while(--ms);
}
//如果实现ns级别的延时,直接NOP(40),40*25ns=1us

这种方法给出了粗略的延时,可以根据需要微调延时精度。

上面文件的源代码,这里

upload 附件:test_51.zip

我使用板子的原理图

upload 附件:SCH_Schematic1_2024-12-22.pdf

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:13
  • 最近打卡:2025-05-01 11:26:42
已绑定手机

9

主题

14

回帖

172

积分

注册会员

积分
172
发表于 2024-12-22 12:03:37 | 显示全部楼层
小*** 发表于 2024-12-22 12:02
# 第一集新建工程相关
- 51的新建工程需要注意Memory model,一般选择XSmall即可,tiny模式串口无法正常工作 ...

图片暂时看不了不知道为啥
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:217
  • 最近打卡:2025-04-29 08:26:08

6

主题

217

回帖

350

积分

中级会员

积分
350
发表于 2024-12-22 12:40:48 | 显示全部楼层

学习中

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:525
  • 最近打卡:2025-05-04 05:16:38
已绑定手机

34

主题

459

回帖

2277

积分

金牌会员

积分
2277
发表于 2024-12-22 13:06:06 | 显示全部楼层
52281*** 发表于 2024-12-20 10:34
学习打卡区在那里?

论坛主页下边 1.png
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:79
  • 最近打卡:2025-05-01 10:17:09
已绑定手机

2

主题

27

回帖

269

积分

中级会员

积分
269
发表于 2024-12-22 14:19:28 | 显示全部楼层
定时器编译警告,哪里出错了
找到问题了,原来是魔法棒里设置的4字节中断不打√

ai8051.rar

91.48 KB, 下载次数: 146

回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-4 15:18 , Processed in 0.333273 second(s), 133 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表