接着看exti.c:
//<<AICUBE_USER_HEADER_REMARK_BEGIN>>
////////////////////////////////////////
// 在此添加用户文件头说明信息
// 文件名称: exti.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
// 1. (2026-03-04) 创建文件
////////////////////////////////////////
//<<AICUBE_USER_HEADER_REMARK_END>>
#include "config.h"
//<<AICUBE_USER_INCLUDE_BEGIN>>
// 在此添加用户头文件包含
#include "key.h"
#include "led.h"
//<<AICUBE_USER_INCLUDE_END>>
//<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
// 在此添加用户全局变量定义、用户宏定义以及函数声明
//<<AICUBE_USER_GLOBAL_DEFINE_END>>
////////////////////////////////////////
// 外部中断INT0初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void EXTI0_Init(void)
{
INT0_FallingRisingInt(); //设置外部中断为边沿中断 (上升沿+下降沿)
INT0_SetIntPriority(0); //设置中断为最低优先级
INT0_EnableInt(); //使能外部中断
//<<AICUBE_USER_EXTI0_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_EXTI0_INITIAL_END>>
}
////////////////////////////////////////
// 外部中断INT1初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void EXTI1_Init(void)
{
INT1_FallingRisingInt(); //设置外部中断为边沿中断 (上升沿+下降沿)
INT1_SetIntPriority(0); //设置中断为最低优先级
INT1_EnableInt(); //使能外部中断
//<<AICUBE_USER_EXTI1_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_EXTI1_INITIAL_END>>
}
////////////////////////////////////////
// 外部中断INT0中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void EXTI0_ISR(void) interrupt INT0_VECTOR
{
//<<AICUBE_USER_EXTI0_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
//对应P32---K3
if(KEY3==0)
{
delay_ms(10);
if(KEY3==0)
{
LED3=!LED3;
printf_usb("K3(P32)按下!\r\n"); // 发送字符串“K3(P32)按下!”
}
}
//<<AICUBE_USER_EXTI0_ISR_CODE1_END>>
}
////////////////////////////////////////
// 外部中断INT1中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void EXTI1_ISR(void) interrupt INT1_VECTOR
{
//<<AICUBE_USER_EXTI1_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
//对应P33---K4
if(KEY4==0)
{
delay_ms(10);
if(KEY4==0)
{
LED4=!LED4;
printf_usb("K4(P33)按下!\r\n"); // 发送字符串“K4(P33)按下!”
}
}
//<<AICUBE_USER_EXTI1_ISR_CODE1_END>>
}
//<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
// 在此添加用户函数实现代码
//<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>
实验现象也和我们预期的一样:
顺利结束本实验
上面这个外部中断和普通IO口中断,我的旧试验箱有个现象:
按1下开关,有时候会表现为按了2次,我把消抖时间延长到40毫秒
也没有什么改善,这个现象在STC的Ai8051U试验箱和STC的32G12K128试验箱上都没有出现过
可能开关的种类也有影响,如果是实用项目,就一定要解决才行生产.........暂且搁置
今天我们继续学习15.1-定时器中断实验-简介
本讲主要内容
1.实验介绍
2.硬件设计
3.软件设计
4.实验现象
Ai8051U系列单片机内部设置了6个24位定时器/计数器(8位预分频+16位计)
数)。6个16位定时器TO、T1、T2、T3、T4和T11都具有计数方式和定时方式两种工作方式。
1.2 实验目的
通过定时器TO、T1、T2、T3让D1指示灯间隔100ms闪烁,D2间隔200ms闪烁,D3间隔300ms闪烁,D4间隔400ms闪烁。
本实验使用到硬件资源如下:
(1)定时器
(2)GPIO
(3)LED模块
重点看AiCube配置:
定时器设置:
最重要的是timer.c函数:
//<<AICUBE_USER_HEADER_REMARK_BEGIN>>
////////////////////////////////////////
// 在此添加用户文件头说明信息
// 文件名称: timer.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
// 1. (2026-03-05) 创建文件
////////////////////////////////////////
//<<AICUBE_USER_HEADER_REMARK_END>>
#include "config.h"
//<<AICUBE_USER_INCLUDE_BEGIN>>
// 在此添加用户头文件包含
#include "led.h"
//<<AICUBE_USER_INCLUDE_END>>
//<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
// 在此添加用户全局变量定义、用户宏定义以及函数声明
//<<AICUBE_USER_GLOBAL_DEFINE_END>>
////////////////////////////////////////
// 定时器0初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_Init(void)
{
#define T0_PSCR (1)
#define T0_RELOAD (65536 - (float)SYSCLK / 12 / (T0_PSCR + 1) * 10 / 1000) //定时周期10毫秒
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开始运行
//<<AICUBE_USER_TIMER0_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_TIMER0_INITIAL_END>>
}
////////////////////////////////////////
// 定时器1初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER1_Init(void)
{
#define T1_PSCR (1)
#define T1_RELOAD (65536 - (float)SYSCLK / 12 / (T1_PSCR + 1) * 20 / 1000) //定时周期20毫秒
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开始运行
//<<AICUBE_USER_TIMER1_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_TIMER1_INITIAL_END>>
}
////////////////////////////////////////
// 定时器2初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER2_Init(void)
{
#define T2_PSCR (2)
#define T2_RELOAD (65536 - (float)SYSCLK / 12 / (T2_PSCR + 1) * 30 / 1000) //定时周期30毫秒
TIMER2_TimerMode(); //设置定时器2为定时模式
TIMER2_12TMode(); //设置定时器2为12T模式
TIMER2_EnableInt(); //使能定时器2中断
TIMER2_SetPrescale(T2_PSCR); //设置定时器2的8位预分频
TIMER2_SetReload16(T2_RELOAD); //设置定时器2的16位重载值
TIMER2_Run(); //定时器2开始运行
//<<AICUBE_USER_TIMER2_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_TIMER2_INITIAL_END>>
}
////////////////////////////////////////
// 定时器3初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER3_Init(void)
{
#define T3_PSCR (20)
#define T3_RELOAD (65536 - (float)SYSCLK / 12 / (T3_PSCR + 1) * 400 / 1000) //定时周期400毫秒
TIMER3_TimerMode(); //设置定时器3为定时模式
TIMER3_12TMode(); //设置定时器3为12T模式
TIMER3_EnableInt(); //使能定时器3中断
TIMER3_SetPrescale(T3_PSCR); //设置定时器3的8位预分频
TIMER3_SetReload16(T3_RELOAD); //设置定时器3的16位重载值
TIMER3_Run(); //定时器3开始运行
//<<AICUBE_USER_TIMER3_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_TIMER3_INITIAL_END>>
}
////////////////////////////////////////
// 定时器0中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_ISR(void) interrupt TMR0_VECTOR
{
//<<AICUBE_USER_TIMER0_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码printf("KEY Work from KS%02X.\r\n", i);
static u8 i=0; //LED1每隔1000ms切换1次
i++;
if(i>10)
{
i=0;
LED1=!LED1;
printf_usb("定时器0设定1秒时间到 ! \r\n");
}
//<<AICUBE_USER_TIMER0_ISR_CODE1_END>>
}
////////////////////////////////////////
// 定时器1中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER1_ISR(void) interrupt TMR1_VECTOR
{
//<<AICUBE_USER_TIMER1_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
static u8 j=0; //LED2每隔2000ms切换1次
j++;
if(j>10)
{
j=0;
LED2=!LED2;
printf_usb("定时器1设定2秒时间到 ! \r\n");
}
//<<AICUBE_USER_TIMER1_ISR_CODE1_END>>
}
////////////////////////////////////////
// 定时器2中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER2_ISR(void) interrupt TMR2_VECTOR
{
//<<AICUBE_USER_TIMER2_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
static u8 k=0; //LED3每隔3000ms切换1次
k++;
if(k>10)
{
k=0;
LED3=!LED3;
printf_usb("定时器2设定3秒时间到 ! \r\n");
}
//<<AICUBE_USER_TIMER2_ISR_CODE1_END>>
}
////////////////////////////////////////
// 定时器3中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER3_ISR(void) interrupt TMR3_VECTOR
{
//<<AICUBE_USER_TIMER3_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
static u8 h=0; //LED4每隔4000ms切换1次
h++;
if(h>10)
{
h=0;
LED4=!LED4;
printf_usb("定时器3设定4秒时间到 ! \r\n");
}
//<<AICUBE_USER_TIMER3_ISR_CODE1_END>>
}
//<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
// 在此添加用户函数实现代码
//<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>
下载后一切顺利,USB-CDC也能顺利工作
目前这块老普中 HC6800-ES V2.0 除了按键,特别是外部中断和IO中断实验有点问题,其他都一切正常,可见普中产品的质量
还是很🐮的,毕竟是10年前的产品,翻出来立马能用,厉害!
16.1-PWM呼吸灯实验-简介
现在我们能输出2中电平,0V 或者高电平5V(3.3V)
我需要输出1.5V ,怎么办?
2条路:芯片有2个办法:1是DAC ,2 是PWM
我们控制PWM的占空比:
假设频率是1K,占空比是50% 如果是3.3V供电,输出大约就是1.5V
占空比加大,输出电压就大,当然我们还是输出数字信号
本讲主要内容
1.实验介绍
2.硬件设计
3.软件设计
4.实验现象
Ai8051U系列单片机内部集成了3组可编程计数器阵列(PCA/CCP/PWM)模块可用于软件定时器、外部脉冲捕获、高速脉冲输出和PWM 脉宽调制输出。
PCA内部含有一个特殊的16位计数器,3组PCA模块均与之相连接。