zhp
发表于 2025-3-31 11:44:55
神农鼎的原始代码中:
使用按位取反符号“~”,对单个的端口进行取反操作是没问题的;
按位取反符号“~”和逻辑取反“!”,对单个可以位寻址的端口进行操作,效果相同
INT0 和 INT1 中断代码,看不到预期的现象,是由于按键没有去抖动引起的
神农鼎
发表于 2025-3-31 11:54:40
国学芯用 发表于 2025-3-31 11:15
//学习 AiCube
神农鼎的原始代码中:
使用按位取反符号“~”,对单个可以位寻址的端口进行取反操作是没问题的;
按位取反符号“~”和逻辑取反“!”,对单个可以位寻址的端口进行操作,效果相同
INT0 和 INT1 中断代码,看不到预期的现象,是由于按键没有去抖动引起的
神农鼎
发表于 2025-3-31 15:09:23
https://www.stcaimcu.com/data/download/Datasheet/AI8051U.pdf
见最新 数据手册
kaily
发表于 2025-3-31 15:09:32
////////////////////////////////////////
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
// 1. (2025-03-31) 创建文件
////////////////////////////////////////
#include "config.h" //默认已包含stdio.h、intrins.h、ai_usb.h等头文件
bit t0_flag = 0; //定义1个位变量,T0事件位变量标志,记录定时器0已产生中断
// 供主循环查询定时器0是否已产生中断,在主循环中处理定时器0的中断事件任务,不堵塞其他中断
bit t1_flag = 0; //定义1个位变量,T1事件位变量标志,记录定时器1已产生中断
// 供主循环查询定时器1是否已产生中断,在主循环中处理定时器1的中断事件任务,不堵塞其他中断
////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
SYS_Init();
P40 = 0; //给LED灯供电
while (1)
{
if(t0_flag) //主循环中查询,定时器0是否已产生中断,是否有需要处理的定时器0事件
{
t0_flag = 0; //清0,T0事件位变量标志
printf_usb("Timer0!\r\n");
//向电脑USB-CDC串口助手输出“Timer0!”字符串,代表主循环在处理T0不急的任务
}
if(t1_flag) //主循环中查询,定时器1是否已产生中断,是否有需要处理的定时器1事件
{
t1_flag = 0; //清0,T1事件位变量标志
printf_usb("Timer1!\r\n");
//向电脑USB-CDC串口助手输出“Timer1!”字符串,代表主循环在处理T1不急的任务
}
USBLIB_OUT_Done(); //查询方式处理USB接收的数据
}
}
////////////////////////////////////////
// 系统初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void SYS_Init(void)
{
EnableAccessXFR(); //使能访问扩展XFR
AccessCodeFastest(); //设置最快速度访问程序代码
AccessIXramFastest(); //设置最快速度访问内部XDATA
IAP_SetTimeBase(); //设置IAP等待参数,产生1us时基
P0M0 = 0x00; P0M1 = 0x00; //初始化P0口为准双向口模式
P1M0 = 0x00; P1M1 = 0x00; //初始化P1口为准双向口模式
P2M0 = 0x00; P2M1 = 0x00; //初始化P2口为准双向口模式
P3M0 = 0x00; P3M1 = 0x00; //初始化P3口为准双向口模式
P4M0 = 0x00; P4M1 = 0x00; //初始化P4口为准双向口模式
P5M0 = 0x00; P5M1 = 0x00; //初始化P5口为准双向口模式
P6M0 = 0x00; P6M1 = 0x00; //初始化P6口为准双向口模式
P7M0 = 0x00; P7M1 = 0x00; //初始化P7口为准双向口模式
TIMER0_Init(); //定时器0初始化
TIMER1_Init(); //定时器1初始化
USBLIB_Init(); //USB库初始化
EnableGlobalInt(); //使能全局中断
}
////////////////////////////////////////
// 毫秒延时函数
// 入口参数: ms (设置延时的毫秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_ms(uint16_t ms)
{
uint16_t i;
do
{
i = MAIN_Fosc / 6000;
while (--i);
} while (--ms);
}
////////////////////////////////////////
// 定时器0中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_ISR(void) interrupt TMR0_VECTOR
{
P00 = ~P00; //P00灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
//以上程序代表部分需特急处理的中断事件,可在中断服务程序中直接处理
//但时间不要太长,否则会影响其他中断事件的实时响应速度
t0_flag = 1; // t0_flag置1是通知主循环处理部分T0中断事件不需要特急处理的任务
//置1,记录定时器0已产生中断,供主循环查询判断有无需处理的定时器0任务
}
////////////////////////////////////////
// 定时器1中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER1_ISR(void) interrupt TMR1_VECTOR
{
P07 = ~P07; //P07灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
//以上程序代表部分需特急处理的中断事件,可在中断服务程序中直接处理
//但时间不要太长,否则会影响其他中断事件的实时响应速度
t1_flag = 1; // t1_flag置1是通知主循环处理部分T1中断事件不需要特急处理的任务
//置1,记录定时器1已产生中断,供主循环查询判断有无需处理的定时器1任务
}
////////////////////////////////////////
// 定时器0初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_Init(void)
{
#define T0_PSCR 102
#define T0_RELOAD (65536 - SYSCLK / 12 / (T0_PSCR + 1) * 2 / 1)
TIMER0_TimerMode(); //设置定时器0为定时模式
TIMER0_12TMode(); //设置定时器0为12T模式
TIMER0_Mode0(); //设置定时器0为模式0 (16位自动重载模式)
TIMER0_DisableGateINT0(); //禁止定时器0门控
TIMER0_SetIntPriority(0); //设置中断为最低优先级
TIMER0_EnableInt(); //使能定时器0中断
TIMER0_SetPrescale(T0_PSCR); //设置定时器0的8位预分频
TIMER0_SetReload16(T0_RELOAD); //设置定时器0的16位重载值
TIMER0_Run(); //定时器0开始运行
}
////////////////////////////////////////
// 定时器1初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER1_Init(void)
{
#define T1_PSCR 25
#define T1_RELOAD (65536 - SYSCLK / 12 / (T1_PSCR + 1) * 500 / 1000)
TIMER1_TimerMode(); //设置定时器1为定时模式
TIMER1_12TMode(); //设置定时器1为12T模式
TIMER1_Mode0(); //设置定时器1为模式0 (16位自动重载模式)
TIMER1_DisableGateINT1(); //禁止定时器1门控
TIMER1_SetIntPriority(0); //设置中断为最低优先级
TIMER1_EnableInt(); //使能定时器1中断
TIMER1_SetPrescale(T1_PSCR); //设置定时器1的8位预分频
TIMER1_SetReload16(T1_RELOAD); //设置定时器1的16位重载值
TIMER1_Run(); //定时器1开始运行
}
////////////////////////////////////////
// USB库初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_Init(void)
{
usb_init(); //初始化USB模块
USB_SetIntPriority(0); //设置中断为最低优先级
set_usb_ispcmd("@STCISP#"); //设置USB不停电下载命令
}
////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
}
////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
if (bUsbOutReady) //查询是否有接收到数据
{
USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试
usb_OUT_done(); //当前包的数据处理完成
}
}
神农鼎
发表于 2025-4-7 13:20:23
利用 AiCube@AIapp-ISP V6.95M,
智能配置开发工具启动程序框架自动生成器,实现如下的实验:
32位8051单片机入门的第一个完整的C语言程序,printf_usb("Hello World !\r\n")
https://v.stcai.com/sv/426d0d7d-1963d548feb/426d0d7d-1963d548feb.mp4
AiCube 实验一:直接 printf_usb("Hello World !\r\n")
32位8051单片机入门的第一个完整的C语言程序
AiCube 实验二:查询方式,查询到电脑命令后,
printf_usb("Hello World !\r\n")或其他
AiCube 实验三:中断方式,单片机USB中断接收服务函数收到命令后,
printf_usb("Hello World !\r\n")或其他
以下是纯手敲代码:
实验一:printf_usb("Hello World !\r\n"),第一个完整的C语言程序
实验二: 查询方式,查询到电脑命令后,printf_usb("Hello World !\r\n")或其他
实验三: 中断方式,单片机USB中断接收服务函数收到命令后,
printf_usb("Hello World !\r\n")或其他
https://v.stcai.com/sv/6707e7ef-1960e65e764/6707e7ef-1960e65e764.mp4
神农鼎
发表于 2025-4-7 14:59:16
RTC的演示程序,AiCube 搭建
////////////////////////////////////////
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
// 1. (2025-04-07) 创建文件
////////////////////////////////////////
#include "config.h" //默认已包含stdio.h、intrins.h、ai_usb.h等头文件
bit fAlarm = 0; //RTC闹钟查询标志,在中断程序中设置,主循环中查询并清除
bit fDay = 0; //RTC天查询标志,在中断程序中设置,主循环中查询并清除
bit fHour = 0; //RTC小时查询标志,在中断程序中设置,主循环中查询并清除
bit fMinute = 0; //RTC分钟查询标志,在中断程序中设置,主循环中查询并清除
bit fSecond = 0; //RTC秒钟查询标志,在中断程序中设置,主循环中查询并清除
////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
SYS_Init();
while (1)
{
if (fAlarm) //判断闹钟查询标志
{
fAlarm = 0; //清除闹钟查询标志
printf_usb("闹钟中断\r\n");
}
if (fDay) //判断天查询标志
{
fDay = 0; //清除天查询标志
printf_usb("RTC天中断\r\n");
}
if (fHour) //判断小时查询标志
{
fHour = 0; //清除小时查询标志
printf_usb("RTC小时中断\r\n");
}
if (fMinute) //设置分钟查询标志
{
fMinute = 0; //清除分钟查询标志
printf_usb("RTC分钟中断\r\n");
}
if (fSecond) //设置秒查询标志
{
fSecond = 0; //清除秒查询标志
printf_usb("RTC秒中断\r\n");
printf_usb("20%d-%d-%d %d:%d:%d\r\n", RTC_ReadYear(),
RTC_ReadMonth(),
RTC_ReadDay(),
RTC_ReadHour(),
RTC_ReadMinute(),
RTC_ReadSecond());
}
USBLIB_OUT_Done(); //查询方式处理USB接收的数据
}
}
////////////////////////////////////////
// 系统初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void SYS_Init(void)
{
EnableAccessXFR(); //使能访问扩展XFR
AccessCodeFastest(); //设置最快速度访问程序代码
AccessIXramFastest(); //设置最快速度访问内部XDATA
IAP_SetTimeBase(); //设置IAP等待参数,产生1us时基
P0M0 = 0x00; P0M1 = 0x00; //初始化P0口为准双向口模式
P1M0 = 0x00; P1M1 = 0x00; //初始化P1口为准双向口模式
P2M0 = 0x00; P2M1 = 0x00; //初始化P2口为准双向口模式
P3M0 = 0x00; P3M1 = 0x00; //初始化P3口为准双向口模式
P4M0 = 0x00; P4M1 = 0x00; //初始化P4口为准双向口模式
P5M0 = 0x00; P5M1 = 0x00; //初始化P5口为准双向口模式
P6M0 = 0x00; P6M1 = 0x00; //初始化P6口为准双向口模式
P7M0 = 0x00; P7M1 = 0x00; //初始化P7口为准双向口模式
RTC_Init(); //RTC初始化
USBLIB_Init(); //USB库初始化
EnableGlobalInt(); //使能全局中断
}
////////////////////////////////////////
// 毫秒延时函数
// 入口参数: ms (设置延时的毫秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_ms(uint16_t ms)
{
uint16_t i;
do
{
i = MAIN_Fosc / 6000;
while (--i);
} while (--ms);
}
////////////////////////////////////////
// RTC中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void RTC_ISR(void) interrupt RTC_VECTOR
{
if (RTC_CheckAlarmFlag()) //判断是否是RTC闹钟中断
{
RTC_ClearAlarmFlag(); //清除中断请求标志位
fAlarm = 1; //设置闹钟查询标志
}
if (RTC_CheckDayFlag()) //判断是否是RTC天中断
{
RTC_ClearDayFlag(); //清除中断请求标志位
fDay = 1; //设置天查询标志
}
if (RTC_CheckHourFlag()) //判断是否是RTC小时中断
{
RTC_ClearHourFlag(); //清除中断请求标志位
fHour = 1; //设置小时查询标志
}
if (RTC_CheckMinuteFlag())//判断是否是RTC分钟中断
{
RTC_ClearMinuteFlag();//清除中断请求标志位
fMinute = 1; //设置分钟查询标志
}
if (RTC_CheckSecondFlag())//判断是否是RTC秒中断
{
RTC_ClearSecondFlag();//清除中断请求标志位
fSecond = 1; //设置秒查询标志
}
}
////////////////////////////////////////
// RTC初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void RTC_Init(void)
{
CLK_X32K_Enable(); //启动外部32768晶振
CLK_X32K_FullGain(); //振荡器高增益
CLK_X32K_WaitStable(); //等待振荡器稳定
RTC_CLK_X32K(); //RTC使用外部32768当作时钟源
RTC_SetAlarmHour(7); //设置RTC闹钟的小时
RTC_SetAlarmMinute(0); //设置RTC闹钟的分钟
RTC_SetAlarmSecond(0); //设置RTC闹钟的秒
RTC_SetAlarmSSecond(0); //初始化RTC闹钟的次秒
RTC_SetYear(25); //设置RTC的年
RTC_SetMonth(4); //设置RTC的月
RTC_SetDay(7); //设置RTC的日
RTC_SetHour(13); //设置RTC的小时
RTC_SetMinute(18); //设置RTC的分钟
RTC_SetSecond(40); //设置RTC的秒
RTC_SetSSecond(0); //初始化RTC的次秒
RTC_Run(); //启动RTC
RTC_SyncInitial(); //同步RTC的初始值
while (RTC_IsSyncing()); //等待同步完成
RTC_SetIntPriority(0); //设置中断为最低优先级
RTC_EnableAlarmInt(); //使能RTC闹钟中断
RTC_EnableDayInt(); //使能RTC天中断
RTC_EnableHourInt(); //使能RTC小时中断
RTC_EnableMinuteInt(); //使能RTC分钟中断
RTC_EnableSecondInt(); //使能RTC秒中断
}
////////////////////////////////////////
// USB库初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_Init(void)
{
usb_init(); //初始化USB模块
USB_SetIntPriority(0); //设置中断为最低优先级
set_usb_ispcmd("@STCISP#"); //设置USB不停电下载命令
}
////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
}
////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
if (bUsbOutReady) //查询是否有接收到数据
{
USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试
usb_OUT_done(); //当前包的数据处理完成
}
}
草木灰06
发表于 2025-4-8 14:30:44
学习了 收藏
jackfangxq
发表于 2025-4-8 16:13:46
神农鼎 发表于 2025-4-7 13:20
实验一:printf_usb("Hello World !\r\n"),第一个完整的C语言程序
实验二: 查询方式,查询到电脑命令后, ...
请问手册中的程序代码怎么复制粘贴的?谢谢
神农鼎
发表于 2025-4-8 20:37:27
jackfangxq 发表于 2025-4-8 16:13
请问手册中的程序代码怎么复制粘贴的?谢谢
QQ或微信截图工具中,有个【转文字】功能
神农鼎
发表于 2025-4-11 19:45:30
汇编语言 实验
14.14深圳大学 I/O 口实验--位操作模式读取按键状态并点灯
14.14.6实验1: 位操作,用USB直接仿真来调试
;IO模式读取按键状态并点灯(位操作)
$INCLUDE(AI8051U.INC) ;包含AI8051U的头文件
;------------------------------------------------
ORG 0000H ;程序复位地址
RESET:
SETB EAXFR ;允许访问扩展的特殊寄存器,XFR
MOV WTST,#00H ;设置取程序代码等待时间,赋值为 0 表示不等待,程序以最快速度运行
MOV CKCON,#00H ;设置访问片内的 xdata 速度,赋值为 0 表示用最快速度访问,不增加额外的等待时间
MOV P0M0,#38H ;设置P03、P04为推挽输出,P05为开漏输出,其余为准双向口模式
MOV P0M1,#20H
MOV P1M0,#00H ;设置 P1 口为准双向口模式
MOV P1M1,#00H
MOV P2M0,#00H ;设置 P2 口为准双向口模式
MOV P2M1,#00H
MOV P3M0,#30H ;P30、P31为高阻输入,P32为准双向口、P33为高阻输入、P34和P35为开漏输出
MOV P3M1,#3BH
MOV P4M0,#00H ;设置 P4 口为准双向口模式
MOV P4M1,#00H
MOV P5M0,#00H ;设置 P5 口为准双向口模式
MOV P5M1,#00H
MOV P6M0,#00H ;设置 P6 口为准双向口模式
MOV P6M1,#00H
MOV P7M0,#00H ;设置 P7 口为准双向口模式
MOV P7M1,#00H
MOV WR0,#WORD2 P3PU ;打开P33、P34、P35的内部上拉电阻,并且仅修改这三个I/O的上拉电阻打开状态
MOV WR2,#WORD0 P3PU
MOV A,#38H
MOV @DR0,R11
LCALL DELAY1MS ;延时1ms,等待IO口电平稳定,因为前面刚改变了模式
;立刻读可能会读到错误的电平,所以需要先等待电平变化稳定后再读
CLR P40 ;打开LED部分的供电
;------------------------------------------------
MAINLOOP:
JNB P3.2,P32ISLOW ;判断P32的电平
P32ISHIGH:
SETB P0.2 ;P32为高电平,则LED02灭
SJMP CHECKP33 ;跳转到判断P33
P32ISLOW:
CLR P0.2 ;P32为低电平,则LED02亮
CHECKP33:
JNB P3.3,P33ISLOW ;判断P33的电平
P33ISHIGH:
SETB P0.3 ;P33为高电平,则LED03灭
SJMP CHECKP34 ;跳转到判断P34
P33ISLOW:
CLR P0.3 ;P33为低电平,则LED03亮
CHECKP34:
JNB P3.4,P34ISLOW ;判断P34的电平
P34ISHIGH:
SETB P0.4 ;P34为高电平,则LED04灭
SJMP CHECKP35 ;跳转到判断P35
P34ISLOW:
CLR P0.4 ;P34为低电平,则LED04亮
CHECKP35:
JNB P3.5,P35ISLOW ;判断P35的电平
P35ISHIGH:
SETB P0.5 ;P35为高电平,则LED05灭
SJMP MAINLOOP ;跳回到主循环开始的地方继续运行程序
P35ISLOW:
CLR P0.5 ;P35为低电平,则LED05亮
SJMP MAINLOOP ;跳回到主循环开始的地方继续运行程序
;------------------------------------------------
DELAY1MS: ;@40.000MHz
PUSH DR0
MOV WR0,#0
MOV WR2,#9998
NEXT:
DEC DR0,#1
JNE NEXT
POP DR0
RET
;------------------------------------------------
END