37. 比较器
采用adc采集ntc电压,并与内部1.9V比较,由于测试时室温高,所以直接用镊子短接ntc两端,瞬间触发P47的led点亮~
课后练习只需将 ADC_CONTR 值改为 0x80 选择 P1.0 ADC 通道即可
#include "cmp.h"
void init_cmp()
{
ADC_CONTR = 0x83; // 打开 ADC_POWER 和 P1.3 ADC 通道
CMPEXCFG = 0x00;
//CMPEXCFG |= 0x40; //比较器DC迟滞输入选择,0:0mV; 0x40:10mV; 0x80:20mV; 0xc0:30mV
//CMPEXCFG &= ~0x04; //P3.6为CMP-输入脚
CMPEXCFG |= 0x04; // 内部1.19V参考电压为CMP-输入脚
// CMPEXCFG &= ~0x03; //P3.7为CMP+输入脚
//CMPEXCFG |= 0x01; //P5.0为CMP+输入脚
//CMPEXCFG |= 0x02; //P5.1为CMP+输入脚
CMPEXCFG |= 0x03; // ADC输入脚为CMP+输入脚
CMPCR2 = 0x00;
INVCMPO = 0; // 比较器正向输出
//INVCMPO = 1; //比较器反向输出
DISFLT = 0; // 使能0.1us滤波
//DISFLT = 1; //禁止0.1us滤波
//CMPCR2 &= ~0x3f; //比较器结果直接输出
CMPCR2 |= 0x10; // 比较器结果经过16个去抖时钟后输出
CMPCR1 = 0x00;
//PIE = 0; //禁止比较器上升沿中断
PIE = 1; // 使能比较器上升沿中断
//NIE = 0; //禁止比较器下降沿中断
NIE = 1; // 使能比较器下降沿中断
//CMPOE = 0; //禁止比较器输出
CMPOE = 1; // 使能比较器输出
CMPO_S = 0; // 选择P3.4作为比较器输出脚
//CMPO_S = 1; //选择P4.1作为比较器输出脚
CMPEN = 1; // 使能比较器模块
}
void CMP_Isr() interrupt 21
{
CMPIF = 0; // 清中断标志
P47 = CMPRES; // 中断方式读取比较器比较结果
}
38. 内部EEPROM
在 EEPROM 中存储断电次数,EEPROM 设置为1K
#include "pref.h"
#include "digital_display.h"
#include "timer.h"
#include "ntc.h"
#include "bee.h"
#include <STDIO.H>
#include "cmp.h"
#include "internal_eeprom.h"
bit B_1ms; // 1ms标志
void sys_init();
void init_usb();
#define FLAG_ADDR 512 // 标记位起始地址
#define DATA_ADDR 0 // 数据位起始地址
void main()
{
u8 i;
sys_init();
init_cmp();
init_adc();
init_time0();
digital_display_init();
init_usb();
EA = 1; // 打开总中断
digital_display_black();
internal_eeprom_idle();
if (internal_eeprom_read(FLAG_ADDR) != 0x2A)
{
internal_eeprom_erasure(FLAG_ADDR);
internal_eeprom_erasure(DATA_ADDR);
internal_eeprom_write(FLAG_ADDR, 0x2A);
internal_eeprom_write(DATA_ADDR, 1);
}
i = internal_eeprom_read(DATA_ADDR);
digital_display_set(i++);
internal_eeprom_erasure(DATA_ADDR);
internal_eeprom_write(DATA_ADDR, i);
// (12*32768*WDT_PS) / MAIN_Fosc
// WDT_PS = 128
// 24M 系统时钟,看门狗计数器溢出时间大概为 2秒
WDT_CONTR = 0x26;
while (1)
{
WDT_CONTR = 0x36;
}
}
void sys_init()
{
WTST = 0;// 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; // 扩展寄存器(XFR)访问使能
CKCON = 0; // 提高访问XRAM速度
{
P0M1 = 0x30;
P0M0 = 0x30; // 设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
P1M1 = 0x30;
P1M0 = 0x30; // 设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
P2M1 = 0x3c;
P2M0 = 0x3c; // 设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
P3M1 = 0x50;
P3M0 = 0x50; // 设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
P4M1 = 0x3c;
P4M0 = 0x3c; // 设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
P5M1 = 0x0c;
P5M0 = 0x0c; // 设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
P6M1 = 0xff;
P6M0 = 0xff; // 设置为漏极开路(实验箱加了上拉电阻到3.3V)
P7M1 = 0x00;
P7M0 = 0x00; // 设置为准双向口
}
}
void init_usb()
{
P3M0 &= ~0x03; // P30,P31 和 USB 的 D-,D+ 共用 PIN 脚
P3M1 |= 0x03;// 需要将 P30,P31 设置为高阻输入模式
IRC48MCR = 0x80; // 使能内部 48M 的 USB 专用 IRC
while (!(IRC48MCR & 0x01))
; // 等待震荡源稳定
USBCLK = 0x00; // 设置 USB 时钟源为内部 48M 的 USB 专用 IRC
USBCON = 0x09; // 使能 USB 功能
usb_init(); // 调用 USB CDC 初始化库函数
EUSB = 1; // 使能 USB 中断
}
/********************** Timer0 1ms中断函数 ************************/
void timer0(void) interrupt 1
{
B_1ms = 1; // 1ms标志
DisplayScan(); // 1ms扫描显示一位
bee_on_1ms();
}
39. DS18B20
#include "pref.h"
#include "digital_display.h"
#include "timer.h"
#include "ntc.h"
#include "bee.h"
#include <STDIO.H>
#include "cmp.h"
#include "internal_eeprom.h"
#include "ds18b20.h"
bit B_1ms; // 1ms标志
u16 msecond;
void sys_init();
void init_usb();
void main()
{
u16 temp;
u8 digital_display_pos = {DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK};
sys_init();
init_time0();
digital_display_init();
init_usb();
EA = 1; // 打开总中断
// (12*32768*WDT_PS) / MAIN_Fosc
// WDT_PS = 128
// 24M 系统时钟,看门狗计数器溢出时间大概为 2秒
WDT_CONTR = 0x26;
while (1)
{
WDT_CONTR = 0x36;
if (B_1ms)
{
B_1ms = 0;
if (++msecond >= 300)
{
msecond = 0;
temp = ds18b20_read_temperature();
if(ds18b20_is_minus())
{
if(temp > 999)
{
digital_display_pos = DIS_;
digital_display_pos = temp / 1000;
}
else
{
digital_display_pos = DIS_BLACK;
digital_display_pos = DIS_;
}
}
else
{
digital_display_pos = DIS_BLACK;
if(temp > 999)
{
digital_display_pos = temp / 1000;
}
else
{
digital_display_pos = DIS_BLACK;
}
}
digital_display_pos = (temp % 1000) / 100;
digital_display_pos = ((temp % 100) / 10) + DIS_DOT;
digital_display_pos = temp % 10;
digital_display_set_pos(
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos
);
}
}
}
}
void sys_init()
{
WTST = 0;// 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; // 扩展寄存器(XFR)访问使能
CKCON = 0; // 提高访问XRAM速度
{
P0M1 = 0x30;
P0M0 = 0x30; // 设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
P1M1 = 0x30;
P1M0 = 0x30; // 设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
P2M1 = 0x3c;
P2M0 = 0x3c; // 设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
P3M1 = 0x50;
P3M0 = 0x50; // 设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
P4M1 = 0x3c;
P4M0 = 0x3c; // 设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
P5M1 = 0x0c;
P5M0 = 0x0c; // 设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
P6M1 = 0xff;
P6M0 = 0xff; // 设置为漏极开路(实验箱加了上拉电阻到3.3V)
P7M1 = 0x00;
P7M0 = 0x00; // 设置为准双向口
}
}
void init_usb()
{
P3M0 &= ~0x03; // P30,P31 和 USB 的 D-,D+ 共用 PIN 脚
P3M1 |= 0x03;// 需要将 P30,P31 设置为高阻输入模式
IRC48MCR = 0x80; // 使能内部 48M 的 USB 专用 IRC
while (!(IRC48MCR & 0x01))
; // 等待震荡源稳定
USBCLK = 0x00; // 设置 USB 时钟源为内部 48M 的 USB 专用 IRC
USBCON = 0x09; // 使能 USB 功能
usb_init(); // 调用 USB CDC 初始化库函数
EUSB = 1; // 使能 USB 中断
}
/********************** Timer0 1ms中断函数 ************************/
void timer0(void) interrupt 1
{
B_1ms = 1; // 1ms标志
DisplayScan(); // 1ms扫描显示一位
bee_on_1ms();
}
推荐优先看的 printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接
https://v.stcai.com/sv/1c5eec2-197fcd9b766/1c5eec2-197fcd9b766.mp4
https://v.stcai.com/sv/1fce8086-197cf2b9dd4/1fce8086-197cf2b9dd4.mp4
39. DS18b20 功能扩展
#include "pref.h"
#include "digital_display.h"
#include "timer.h"
#include "ntc.h"
#include "bee.h"
#include <STDIO.H>
#include "cmp.h"
#include "internal_eeprom.h"
#include "ds18b20.h"
bit B_1ms; // 1ms标志
u16 msecond;
void sys_init();
void init_usb();
void main()
{
u16 temp;
u8 digital_display_pos = {DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK};
u8 serial;
u8 config;
sys_init();
init_time0();
digital_display_init();
init_usb();
EA = 1; // 打开总中断
ds18b20_read_serial(serial);
ds18b20_read_cfg(serial, config);
// 接收任意串口数据后继续执行, 方便调试
while (!bUsbOutReady)
;
printf_usb("\r\nserial: %X %X %X %X %X %X %X %X\r\n", serial, serial, serial, serial, serial, serial, serial, serial);
printf_usb("\r\nconfig: %X %X %X %X %X\r\n", config, config, config, config, config);
digital_display_black();
// (12*32768*WDT_PS) / MAIN_Fosc
// WDT_PS = 128
// 24M 系统时钟,看门狗计数器溢出时间大概为 2秒
WDT_CONTR = 0x26;
while (1)
{
WDT_CONTR = 0x36;
if (B_1ms)
{
B_1ms = 0;
if (++msecond >= 500)
{
msecond = 0;
temp = ds18b20_read_temperature_target(serial);
printf_usb("%0.2f", ((float)temp / 100));
if (ds18b20_is_minus())
{
if (temp > 999)
{
digital_display_pos = DIS_;
digital_display_pos = temp / 1000;
}
else
{
digital_display_pos = DIS_BLACK;
digital_display_pos = DIS_;
}
}
else
{
digital_display_pos = DIS_BLACK;
if (temp > 999)
{
digital_display_pos = temp / 1000;
}
else
{
digital_display_pos = DIS_BLACK;
}
}
digital_display_pos = (temp % 1000) / 100 + DIS_DOT;
digital_display_pos = ((temp % 100) / 10);
digital_display_pos = temp % 10;
digital_display_set_pos(
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos,
digital_display_pos);
usb_OUT_done();
}
if (!P34)
{
// 精度切换
delay_ms(100);
if (!P34)
{
digital_display_set(12345678);
temp = (config & 0x60) >> 5;
if (temp >= 3)
{
temp = 0;
}
else
{
temp++;
}
ds18b20_cfg_ratio(serial, temp);
ds18b20_read_cfg(serial, config);
printf_usb("\r\nconfig: %X %X %X %X %X\r\n", config, config, config, config, config);
while (!P34)
{
WDT_CONTR = 0x36;
}
digital_display_black();
}
}
}
}
}
void sys_init()
{
WTST = 0;// 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; // 扩展寄存器(XFR)访问使能
CKCON = 0; // 提高访问XRAM速度
{
P0M1 = 0x30;
P0M0 = 0x30; // 设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
P1M1 = 0x30;
P1M0 = 0x30; // 设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
P2M1 = 0x3c;
P2M0 = 0x3c; // 设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
P3M1 = 0x50;
P3M0 = 0x50; // 设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
P4M1 = 0x3c;
P4M0 = 0x3c; // 设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
P5M1 = 0x0c;
P5M0 = 0x0c; // 设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
P6M1 = 0xff;
P6M0 = 0xff; // 设置为漏极开路(实验箱加了上拉电阻到3.3V)
P7M1 = 0x00;
P7M0 = 0x00; // 设置为准双向口
}
}
void init_usb()
{
P3M0 &= ~0x03; // P30,P31 和 USB 的 D-,D+ 共用 PIN 脚
P3M1 |= 0x03;// 需要将 P30,P31 设置为高阻输入模式
IRC48MCR = 0x80; // 使能内部 48M 的 USB 专用 IRC
while (!(IRC48MCR & 0x01))
; // 等待震荡源稳定
USBCLK = 0x00; // 设置 USB 时钟源为内部 48M 的 USB 专用 IRC
USBCON = 0x09; // 使能 USB 功能
usb_init(); // 调用 USB CDC 初始化库函数
EUSB = 1; // 使能 USB 中断
}
/********************** Timer0 1ms中断函数 ************************/
void timer0(void) interrupt 1
{
B_1ms = 1; // 1ms标志
DisplayScan(); // 1ms扫描显示一位
bee_on_1ms();
}
#include "ds18b20.h"
sbit DQ = P3 ^ 3; // DS18B20的数据口
bit _MinusFlag; // 负数标志,0:正数,1:负数
bit ds18b20_is_minus()
{
return _MinusFlag;
}
void ds18b20_read_scratchpad(u8 *temperature, u8 *tHL, u8 *cfg, u8 *user, u8 *crc)
{
ds18b20_writebyte(0xBE); // 读取暂存器
temperature = ds18b20_readbyte(); // 读温度低字节
temperature = ds18b20_readbyte(); // 读温度高字节
tHL = ds18b20_readbyte(); // T_H Reg
tHL = ds18b20_readbyte(); // T_L Reg
*cfg = ds18b20_readbyte(); // Config Reg
ds18b20_readbyte(); // FFh
user = ds18b20_readbyte(); // User byte
user = ds18b20_readbyte(); // User byte
*crc = ds18b20_readbyte();
}
void ds18b20_write_scratchpad(u8 *config)
{
ds18b20_writebyte(0x4E); // 写入暂存器
ds18b20_writebyte(config);
ds18b20_writebyte(config);
ds18b20_writebyte(config);
ds18b20_reset();
}
void ds18b20_write_eeprom(u8 *serial)
{
ds18b20_reset();
ds18b20_match_serial(serial);
ds18b20_writebyte(0x48); // 写入EEPROM
while (!DQ)
;
}
u16 ds18b20_read_tempturature()
{
u16 Temperature;
u8 temp;
ds18b20_read_scratchpad(temp, 0, 0, 0, 0);
if (temp & 0xf8) // 判断是否位负数
{
_MinusFlag = 1; // 设置负数标志
Temperature = (temp << 8) | temp;
Temperature = ~Temperature + 1;
Temperature *= 0.625; // 0.0625 * 10,保留1位小数点
}
else
{
_MinusFlag = 0; // 清除负数标志
Temperature = (((temp << 8) | temp) * 6.25); // 0.0625 * 100,保留2位小数点
}
return Temperature;
}
void ds18b20_reset()
{
CY = 1;
while (CY)
{
DQ = 0; // 送出低电平复位信号
delay_us(240); // 延时至少480us
delay_us(240);
DQ = 1; // 释放数据线
delay_us(60);// 等待60us
CY = DQ; // 检测存在脉冲
delay_us(240); // 等待设备释放数据线
delay_us(180);
}
}
void ds18b20_read_serial(u8 *dat)
{
u8 i, j, tmp_u8;
bit tmp_bit;
ds18b20_reset();
ds18b20_writebyte(0xF0); // Search ROM
for (i = 0; i < 8; i++)
{
tmp_u8 = 0;
for (j = 0; j < 8; j++)
{
tmp_bit = ds18b20_readbit(); // B20 TX bit
while (ds18b20_readbit() == tmp_bit) // B20 TX !bit
;
ds18b20_writebit(tmp_bit); // Master TX bit
// printf_usb("%d", tmp_bit);
tmp_u8 >>= 1;
if (tmp_bit)
{
tmp_u8 |= 0x80;
}
}
*dat++ = tmp_u8;
}
}
void ds18b20_match_serial(u8 *dat)
{
u8 i, j, tmp_u8;
ds18b20_reset();
ds18b20_writebyte(0x55); // Match ROM
for (i = 0; i < 8; i++)
{
tmp_u8 = dat;
for (j = 0; j < 8; j++)
{
ds18b20_writebit(tmp_u8 & 0x01); // Master TX bit
tmp_u8 >>= 1;
}
}
}
void ds18b20_writebit(bit b)
{
DQ = 0; // 开始时间片
delay_us(1); // 延时等待
DQ = b;
delay_us(60); // 等待时间片结束
DQ = 1; // 恢复数据线
delay_us(1);// 恢复延时
}
void ds18b20_writebyte(u8 dat)
{
char i;
for (i = 0; i < 8; i++) // 8位计数器
{
DQ = 0; // 开始时间片
delay_us(1); // 延时等待
dat >>= 1; // 送出数据
DQ = CY;
delay_us(60); // 等待时间片结束
DQ = 1; // 恢复数据线
delay_us(1);// 恢复延时
}
}
bit ds18b20_readbit()
{
bit i;
DQ = 0; // 开始时间片
delay_us(1); // 延时等待
DQ = 1; // 准备接收
delay_us(1); // 接收延时
i = DQ;
delay_us(60); // 等待时间片结束
return i;
}
u8 ds18b20_readbyte()
{
u8 i;
u8 dat = 0;
for (i = 0; i < 8; i++) // 8位计数器
{
dat >>= 1;
DQ = 0; // 开始时间片
delay_us(1); // 延时等待
DQ = 1; // 准备接收
delay_us(1); // 接收延时
if (DQ)
dat |= 0x80; // 读取数据
delay_us(60); // 等待时间片结束
}
return dat;
}
void ds18b20_read_cfg(u8 *serial, u8 *cfg)
{
u8 t_threshold, _user;
u8 _config;
ds18b20_reset();
ds18b20_match_serial(serial);
ds18b20_read_scratchpad(0, t_threshold, &_config, _user, 0);
cfg = t_threshold;
cfg = t_threshold;
cfg = _config;
cfg = _user;
cfg = _user;
}
/**
* 0 - 0.5
* 1 - 0.25
* 2 - 0.125
* 3 - 0.0625
*/
void ds18b20_cfg_ratio(u8 *serial, u8 ratio)
{
u8 config;
ds18b20_read_cfg(serial, config);
config = ratio << 5;
ds18b20_reset();
ds18b20_match_serial(serial);
ds18b20_write_scratchpad(config);
ds18b20_write_eeprom(serial);
}
u16 ds18b20_read_temperature_target(u8 *serial)
{
ds18b20_match_serial(serial); // 找指定设备
ds18b20_writebyte(0x44); // 写入转换命令
while (!DQ)
; // 等待转换完成
ds18b20_reset(); // 复位
ds18b20_match_serial(serial); // 找指定设备
return ds18b20_read_tempturature();
}
u16 ds18b20_read_temperature_any()
{
ds18b20_reset(); // 设备复位
ds18b20_writebyte(0xCC); // 跳过ROM命令
ds18b20_writebyte(0x44); // 开始转换命令
while (!DQ)
; // 等待转换完成
ds18b20_reset(); // 设备复位
ds18b20_writebyte(0xCC); // 跳过ROM命令
return ds18b20_read_tempturature(); // 读暂存存储器命令
}
41. 软件模拟SPI
main.c
spi_flash_writebyte(0xAB);
// 3个字节无效数据
spi_flash_readbyte();
spi_flash_readbyte();
spi_flash_readbyte();
// 在 CS 拉高之前,flash会一直输出device id
printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
spi_flash_disable();
spi_flash_writebyte(0x9F);
printf_usb("JEDEC ID: ");
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X \r\n", spi_flash_readbyte());
spi_flash_disable();
spi_flash_writebyte(0x4B);
// 4个字节无效数据
spi_flash_readbyte();
spi_flash_readbyte();
spi_flash_readbyte();
spi_flash_readbyte();
printf_usb("UniqueID: ");
// 64位序列号
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X ", spi_flash_readbyte());
printf_usb("%X \r\n", spi_flash_readbyte());
spi_flash_disable();
spi.c
#define SCLK P25
#define MISO P24
#define MOSI P23
#define CS P22
#define WP P53
void spi_flash_reset()
{
SCLK = 0;
WP = 1;
MISO = 1;
MOSI = 1;
CS = 0;
}
void spi_flash_disable()
{
CS = 1;
}
void spi_flash_writebyte(u8 dat)
{
u8 i;
spi_flash_reset();
for (i = 0; i < 8; i++)
{
if (dat & 0x80)
{
MOSI = 1;
}
else
{
MOSI = 0;
}
SCLK = 0;
SCLK = 1;
dat <<= 1;
}
}
u8 spi_flash_readbyte()
{
u8 dat, i;
spi_flash_reset();
for (i = 0; i < 8; i++)
{
dat <<= 1;
SCLK = 0;
SCLK = 1;
dat |= MISO;
}
return dat;
}
42. 硬件SPI
SPI
#include "spi_flash.h"
#define CS P22
#define MOSI P23
#define MISO P24
#define SCLK P25
#define WP P53
void init_spi_flash()
{
P_SW1 &= 0xF3;// 清除 SPI 功能脚选择位
P_SW1 |= 0x04;// SS=P22 MOSI=P23 MISO=P24 SCLK=P25
SPSTAT = 0xC0;// 清除 SPI 状态寄存器
SSIG = 1; // 忽略 SS 引脚功能,使用 MSTR 确定主、从
DORD = 0; // 从最高位开始传输 SPI 数据
MSTR = 1; // 主机模式
CPOL = 1; // SCLK 空闲为高电平,前时钟沿为下降沿
CPHA = 1; // 数据在 SCLK 的前时钟沿驱动,后时钟沿采样
SPR1 = 0; // SPI 时钟频率
SPR0 = 0; // SPI 输入时钟/4
SPEN = 1; // 使能 SPI
}
void spi_flash_enable()
{
CS = 0;
}
void spi_flash_disable()
{
CS = 1;
}
void spi_flash_writebyte(u8 dat)
{
SPDAT = dat;
while(SPIF == 0);
SPIF = 1;
WCOL = 1;
}
u8 spi_flash_readbyte()
{
SPDAT = 0xFF;
while(SPIF == 0);
SPIF = 1;
WCOL = 1;
return (SPDAT);
}
USART2-SPI
#include "spi_flash.h"
#define CS P22
#define MOSI P23
#define MISO P24
#define SCLK P25
#define WP P53
void init_spi_flash()
{
S2SPI_S1 = 0;
S2SPI_S0 = 1;
S2SM0 = 0;
S2SM1 = 0;
S2REN = 1;
USART2CR1 = 0x10;
USART2CR4 = 0x00;
USART2CR1 |= 0x08;
S2TI = 0;
S2RI = 0;
}
void spi_flash_enable()
{
CS = 0;
}
void spi_flash_disable()
{
CS = 1;
}
void spi_flash_writebyte(u8 dat)
{
S2TI = 0;
S2BUF = dat;
while (!S2TI)
;
}
u8 spi_flash_readbyte()
{
S2TI = 0;
S2BUF = 0xFF;
while (!S2TI)
;
return S2BUF;
}
43. SPI 读写 FLASH 芯片
读取device id
读取 jedec id
读取 unique id
记录开关机次数
printf_usb("device ID: 0x%X\r\n", spi_flash_load_DEVICE_ID());
printf_usb("JEDEC ID: %lX\r\n", spi_flash_load_JEDEC_ID());
spi_flash_load_UNIQUE_ID(tmp);
printf_usb("Unique ID: %lX%lX\n", tmp, tmp);
printf_usb("busy: %d\r\n", spi_flash_check_busy());
spi_flash_read(DAT_ADDR, buf, 2);
printf_usb("%X %d\r\n", buf, buf);
if (buf == 0x8F)
{
printf_usb("found data\r\n");
spi_flash_erase(DAT_ADDR);
buf++;
}
else
{
printf_usb("erase page\r\n");
spi_flash_erase(DAT_ADDR);
buf = 0x8F;
buf = 1;
}
spi_flash_write(DAT_ADDR, buf, 2);
printf_usb("%X %d\r\n", buf, buf);
digital_display_set(buf);
usb_OUT_done();
NTC采集温度并存储最近10次温度数值存储到flash芯片
void clear_temperature()
{
spi_flash_erase(DAT_ADDR);
printf_usb("CLEAR TEMPERATURE DATA!");
}
void print_temperature(u8 *buf, u8 cnt)
{
u8 i;
u16 tmp_u16;
printf_usb(">>>>>>>>>>>>>>>>>>>>>>\r\n");
printf_usb("TEMPERTURE DATA:\r\n");
for (i = 1; i <= cnt; i++)
{
// 高8位地址
tmp_u16 = buf[(i * 2 + 1)] << 8;
// 低8位地址
tmp_u16 |= buf[(i * 2)];
if (tmp_u16 >= 400)
F0 = 0, tmp_u16 -= 400; // 温度 >= 0度
else
F0 = 1, tmp_u16 = 400 - tmp_u16; // 温度 <0度
printf_usb("%2d :%5.1f\r\n", i, ((float)tmp_u16) / 10);
}
printf_usb("<<<<<<<<<<<<<<<<<<<<<<\r\n");
}
void refresh_temperature(BOOL is_print)
{
// W25X40CL
// 1K = 512byte * 2 = 1024byte
// 4KB = 4096byte
// 1页 = 256byte
// 4KB = 16页
// 地址格式(24 位):A23 A22 ... A8 A7 A6 ... A0
// 高 16 位(A23~A8):决定 “哪一页”(比如 A23~A8=0000h,就是第 0 页;A23~A8=0001h,就是第 1 页);
// 低 8 位(A7~A0):决定 “页内的哪个字节”(00h~FFh,对应页内第 0 字节到第 255 字节)。
u8 buf, cnt_temperature, flag; // temperture_9, temperture_8, ... , temperture_0, count, flag
u8 i, tmp_H, tmp_L;
u16 tmp_u16;
spi_flash_read(DAT_ADDR, buf, 22);
printf_usb("readbuf: 0x%X%d\r\n", buf, buf);
flag = buf;
if (flag == 0x80)
{
cnt_temperature = buf;
}
else
{
cnt_temperature = 1;
}
if (is_print)
{
if (flag == 0x80)
{
print_temperature(buf, cnt_temperature);
return;
}
else
{
printf_usb("not found temperture data");
return;
}
}
if (cnt_temperature >= MAX_TEMP_COUNT)
{
cnt_temperature = MAX_TEMP_COUNT;
// 滚动记录
for (i = 1; i < MAX_TEMP_COUNT; i++)
{
buf = buf[(i + 1) * 2];
buf = buf[(i + 1) * 2 + 1];
}
}
tmp_u16 = Get_ADC12bitResult(ADC_CHANNEL_NTC);
printf_usb("adc: %d\r\n", tmp_u16);
if (tmp_u16 < 4096)
{
if (flag == 0x80 && cnt_temperature < MAX_TEMP_COUNT)
{
cnt_temperature += 1;
}
tmp_u16 = get_temperature(tmp_u16);
tmp_H = (u8)(tmp_u16 >> 8);
tmp_L = (u8)(tmp_u16 & 0xFF);
// 高8位地址
buf[(cnt_temperature * 2 + 1)] = tmp_H;
// 低8位地址
buf[(cnt_temperature * 2)] = tmp_L;
buf = 0x80;
buf = cnt_temperature;
spi_flash_erase(DAT_ADDR);
printf_usb("writebuf: 0x%X%d\r\n", buf, buf);
spi_flash_write(DAT_ADDR, buf, 22);
}
else
{
printf_usb("invalid adc data, skip sample");
return;
}
}
47. USB-CDC串口读写 FLASH
读取FLASH芯片地址
u8 i2c_24Cxx_load_device_addr()
{
u8 a2a1a0; // A2/A1/A0 地址位,000~111 共有7钟组合
u8 tmp;
u8 heigh_addr = 0xA0; // 高位地址固定为 1010
for (a2a1a0 = 0; a2a1a0 < 8; a2a1a0++)
{
tmp = heigh_addr | (a2a1a0 << 1);
i2c_24Cxx_start();
if (!i2c_24Cxx_send_byte(tmp & 0xFE)) // 发送器件地址+写选择位
{
i2c_24Cxx_stop();
// 接收到器件 ACK
printf_usb("device addr: 0x%X\r\n", tmp);
return tmp;
}
i2c_24Cxx_stop();
}
50. PWM
//<<AICUBE_USER_HEADER_REMARK_BEGIN>>
////////////////////////////////////////
// 在此添加用户文件头说明信息
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
// 1. (2025-11-24) 创建文件
////////////////////////////////////////
//<<AICUBE_USER_HEADER_REMARK_END>>
#include "config.h" //默认已包含stdio.h、intrins.h等头文件
//<<AICUBE_USER_INCLUDE_BEGIN>>
// 在此添加用户头文件包含
//<<AICUBE_USER_INCLUDE_END>>
//<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
// 在此添加用户全局变量定义、用户宏定义以及函数声明
#define PWM_PERIOD 999 // 设置周期值
u16 PWM1_Duty;
u16 PWM2_Duty;
u16 PWM3_Duty;
u16 PWM4_Duty;
bit PWM1_Flag;
bit PWM2_Flag;
bit PWM3_Flag;
bit PWM4_Flag;
void UpdatePwm(void);
//<<AICUBE_USER_GLOBAL_DEFINE_END>>
////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
//<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
// 在此添加用户主函数初始化代码
//<<AICUBE_USER_MAIN_INITIAL_END>>
SYS_Init();
//<<AICUBE_USER_MAIN_CODE_BEGIN>>
// 在此添加主函数中运行一次的用户代码
//<<AICUBE_USER_MAIN_CODE_END>>
while (1)
{
USBLIB_OUT_Done(); //查询方式处理USB接收的数据
//<<AICUBE_USER_MAIN_LOOP_BEGIN>>
// 在此添加主函数中用户主循环代码
//<<AICUBE_USER_MAIN_LOOP_END>>
}
}
////////////////////////////////////////
// 系统初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void SYS_Init(void)
{
EnableAccessXFR(); //使能访问扩展XFR
AccessCodeFastest(); //设置最快速度访问程序代码
AccessIXramFastest(); //设置最快速度访问内部XDATA
IAP_SetTimeBase(); //设置IAP等待参数,产生1us时基
//<<AICUBE_USER_PREINITIAL_CODE_BEGIN>>
// 在此添加用户预初始化代码
//<<AICUBE_USER_PREINITIAL_CODE_END>>
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口为准双向口模式
PORT0_Init(); //P0口初始化
PORT6_Init(); //P6口初始化
PORT7_Init(); //P7口初始化
TIMER0_Init(); //定时器0初始化
PWMA_Init(); //高级PWMA初始化
delay_ms(1);
USBLIB_Init(); //USB库初始化
delay_ms(1);
//<<AICUBE_USER_INITIAL_CODE_BEGIN>>
// 在此添加用户初始化代码
P40 = 0;
P7 = 0x00;
PWM1_Duty = 249;
PWM2_Duty = 249 * 2;
PWM3_Duty = 249 * 3;
PWM4_Duty = 249 * 4;
UpdatePwm();
//<<AICUBE_USER_INITIAL_CODE_END>>
EnableGlobalInt(); //使能全局中断
USBLIB_WaitConfiged(); //等待USB完成配置
}
////////////////////////////////////////
// 微秒延时函数
// 入口参数: us (设置延时的微秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_us(uint16_t us)
{
do
{
NOP(18); //(MAIN_Fosc + 500000) / 1000000 - 6
} while (--us);
}
////////////////////////////////////////
// 毫秒延时函数
// 入口参数: ms (设置延时的毫秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_ms(uint16_t ms)
{
uint16_t i;
do
{
i = MAIN_Fosc / 6000;
while (--i);
} while (--ms);
}
////////////////////////////////////////
// P0口初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void PORT0_Init(void)
{
SetP0nInitLevelHigh(PIN_ALL); //设置P0初始化电平
SetP0nQuasiMode(PIN_ALL); //设置P0为准双向口模式
DisableP0nPullUp(PIN_ALL); //关闭P0内部上拉电阻
DisableP0nSchmitt(PIN_ALL); //使能P0施密特触发
SetP0nSlewRateNormal(PIN_ALL); //设置P0一般翻转速度
SetP0nDrivingNormal(PIN_ALL); //设置P0一般驱动能力
SetP0nDigitalInput(PIN_ALL); //使能P0数字信号输入功能
//<<AICUBE_USER_PORT0_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_PORT0_INITIAL_END>>
}
////////////////////////////////////////
// P6口初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void PORT6_Init(void)
{
SetP6nInitLevelHigh(PIN_ALL); //设置P6初始化电平
SetP6nQuasiMode(PIN_ALL); //设置P6为准双向口模式
DisableP6nPullUp(PIN_ALL); //关闭P6内部上拉电阻
DisableP6nSchmitt(PIN_ALL); //使能P6施密特触发
SetP6nSlewRateNormal(PIN_ALL); //设置P6一般翻转速度
SetP6nDrivingNormal(PIN_ALL); //设置P6一般驱动能力
SetP6nDigitalInput(PIN_ALL); //使能P6数字信号输入功能
//<<AICUBE_USER_PORT6_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_PORT6_INITIAL_END>>
}
////////////////////////////////////////
// P7口初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void PORT7_Init(void)
{
SetP7nInitLevelHigh(PIN_ALL); //设置P7初始化电平
SetP7nQuasiMode(PIN_ALL); //设置P7为准双向口模式
DisableP7nPullUp(PIN_ALL); //关闭P7内部上拉电阻
DisableP7nSchmitt(PIN_ALL); //使能P7施密特触发
SetP7nSlewRateNormal(PIN_ALL); //设置P7一般翻转速度
SetP7nDrivingNormal(PIN_ALL); //设置P7一般驱动能力
SetP7nDigitalInput(PIN_ALL); //使能P7数字信号输入功能
//<<AICUBE_USER_PORT7_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_PORT7_INITIAL_END>>
}
////////////////////////////////////////
// 定时器0初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_Init(void)
{
#define T0_PSCR (0)
#define T0_RELOAD (65536 - (float)SYSCLK / (T0_PSCR + 1) * 1000 / 1000000)
TIMER0_TimerMode(); //设置定时器0为定时模式
TIMER0_1TMode(); //设置定时器0为1T模式
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>>
}
////////////////////////////////////////
// PWMA初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void PWMA_Init(void)
{
PWMA_C1SwitchP6061(); //设置PWMA通道1数据端口: PWM1P (P6.1), PWM3N (P6.2)
PWMA_C2SwitchP6263(); //设置PWMA通道2数据端口: PWM2P (P6.3), PWM3N (P6.4)
PWMA_C3SwitchP6465(); //设置PWMA通道3数据端口: PWM3P (P6.4), PWM3N (P6.5)
PWMA_C4SwitchP6667(); //设置PWMA通道4数据端口: PWM4P (P6.6), PWM4N (P6.7)
HSPWMA_Disable(); //关闭高速模式,使用同步方式进行初始化
PWMA_InternalClockMode(); //选择内部时钟模式
PWMA_SetClockDivider(0); //设置16位预分频
PWMA_SetReload16(PWM_PERIOD); //设置16位重载值
PWMA_BufferARR(); //使能重载值寄存器预装载功能
PWMA_SetCounter(0); //初始化计数值
PWMA_CC1PDisable(); //关闭通道
PWMA_CC1Output(); //使能通道输出功能
PWMA_CC1PEnable(); //打开通道
PWM_UpdateDuty(PWMA_CH1, 500); //设置通道的PWM占空比
PWMA_OC1REFPWMMode1(); //设置通道输出参考信号为PWM模式1信号
PWMA_BufferCCR1(); //使能CCRn预装载功能
PWMA_CC1PNonInverted(); //设置正极通道输出高电平有效
PWMA_EnablePWM1POutput(); //使能正极通道输出
PWMA_CC1NEnable(); //打开负极通道
PWMA_CC1NNonInverted(); //设置负极通道输出高电平有效
PWMA_EnablePWM1NOutput(); //使能负极通道输出
PWMA_CC2PDisable(); //关闭通道
PWMA_CC2Output(); //使能通道输出功能
PWMA_CC2PEnable(); //打开通道
PWM_UpdateDuty(PWMA_CH2, 500); //设置通道的PWM占空比
PWMA_OC2REFPWMMode1(); //设置通道输出参考信号为PWM模式1信号
PWMA_BufferCCR2(); //使能CCRn预装载功能
PWMA_CC2PNonInverted(); //设置正极通道输出高电平有效
PWMA_EnablePWM2POutput(); //使能正极通道输出
PWMA_CC2NEnable(); //打开负极通道
PWMA_CC2NNonInverted(); //设置负极通道输出高电平有效
PWMA_EnablePWM2NOutput(); //使能负极通道输出
PWMA_CC3PDisable(); //关闭通道
PWMA_CC3Output(); //使能通道输出功能
PWMA_CC3PEnable(); //打开通道
PWM_UpdateDuty(PWMA_CH3, 500); //设置通道的PWM占空比
PWMA_OC3REFPWMMode1(); //设置通道输出参考信号为PWM模式1信号
PWMA_BufferCCR3(); //使能CCRn预装载功能
PWMA_CC3PNonInverted(); //设置正极通道输出高电平有效
PWMA_EnablePWM3POutput(); //使能正极通道输出
PWMA_CC3NEnable(); //打开负极通道
PWMA_CC3NNonInverted(); //设置负极通道输出高电平有效
PWMA_EnablePWM3NOutput(); //使能负极通道输出
PWMA_CC4PDisable(); //关闭通道
PWMA_CC4Output(); //使能通道输出功能
PWMA_CC4PEnable(); //打开通道
PWM_UpdateDuty(PWMA_CH4, 500); //设置通道的PWM占空比
PWMA_OC4REFPWMMode1(); //设置通道输出参考信号为PWM模式1信号
PWMA_BufferCCR4(); //使能CCRn预装载功能
PWMA_CC4PNonInverted(); //设置正极通道输出高电平有效
PWMA_EnablePWM4POutput(); //使能正极通道输出
PWMA_CC4NEnable(); //打开负极通道
PWMA_CC4NNonInverted(); //设置负极通道输出高电平有效
PWMA_EnablePWM4NOutput(); //使能负极通道输出
PWMA_EnableMainOutput(); //使能PWM主输出
PWMA_Run(); //PWMA开始运行
//<<AICUBE_USER_PWM0_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_PWM0_INITIAL_END>>
}
////////////////////////////////////////
// 设置PWM通道输出占空比
// 入口参数: PWMx: (目标PWM组和通道索引)
// nCompare: (PWM占空比值)
// iMode: (PWM输出模式:PWM_MODE1/PWM_MODE2)
// 函数返回: 无
////////////////////////////////////////
void PWM_UpdateDuty(uint8_t PWMx, uint16_t nCompare)
{
switch (PWMx)
{
case PWMA_CH1:
PWMA_SetCCR1Value(nCompare); //设置通道比较值
break;
case PWMA_CH2:
PWMA_SetCCR2Value(nCompare); //设置通道比较值
break;
case PWMA_CH3:
PWMA_SetCCR3Value(nCompare); //设置通道比较值
break;
case PWMA_CH4:
PWMA_SetCCR4Value(nCompare); //设置通道比较值
break;
case PWMB_CH5:
PWMB_SetCCR5Value(nCompare); //设置通道比较值
break;
case PWMB_CH6:
PWMB_SetCCR6Value(nCompare); //设置通道比较值
break;
case PWMB_CH7:
PWMB_SetCCR7Value(nCompare); //设置通道比较值
break;
case PWMB_CH8:
PWMB_SetCCR8Value(nCompare); //设置通道比较值
break;
}
}
////////////////////////////////////////
// 读取PWM通道捕获值
// 入口参数: PWMx: (目标PWM组和通道索引)
// 函数返回: 捕获值
////////////////////////////////////////
uint16_t PWM_ReadCapture(uint8_t PWMx)
{
uint16_t cap;
switch (PWMx)
{
case PWMA_CH1:cap = PWMA_ReadCCR1Value(); break;
case PWMA_CH2:cap = PWMA_ReadCCR2Value(); break;
case PWMA_CH3:cap = PWMA_ReadCCR3Value(); break;
case PWMA_CH4:cap = PWMA_ReadCCR4Value(); break;
case PWMB_CH5:cap = PWMB_ReadCCR5Value(); break;
case PWMB_CH6:cap = PWMB_ReadCCR6Value(); break;
case PWMB_CH7:cap = PWMB_ReadCCR7Value(); break;
case PWMB_CH8:cap = PWMB_ReadCCR8Value(); break;
default: cap = 0;
}
return cap;
}
////////////////////////////////////////
// 设置高速模式PWM通道输出占空比
// 入口参数: PWMx: (目标PWM组和通道索引)
// nCompare: (PWM占空比值)
// 函数返回: 无
////////////////////////////////////////
void HSPWM_UpdateDuty(uint8_t PWMx, uint16_t nCompare)
{
switch (PWMx)
{
case PWMA_CH1:
HSPWMA_SetCCR1Value(nCompare);//设置通道比较值
break;
case PWMA_CH2:
HSPWMA_SetCCR2Value(nCompare);//设置通道比较值
break;
case PWMA_CH3:
HSPWMA_SetCCR3Value(nCompare);//设置通道比较值
break;
case PWMA_CH4:
HSPWMA_SetCCR4Value(nCompare);//设置通道比较值
break;
case PWMB_CH5:
HSPWMB_SetCCR5Value(nCompare);//设置通道比较值
break;
case PWMB_CH6:
HSPWMB_SetCCR6Value(nCompare);//设置通道比较值
break;
case PWMB_CH7:
HSPWMB_SetCCR7Value(nCompare);//设置通道比较值
break;
case PWMB_CH8:
HSPWMB_SetCCR8Value(nCompare);//设置通道比较值
break;
}
}
////////////////////////////////////////
// 读取高速模式PWM通道捕获值
// 入口参数: PWMx: (目标PWM组和通道索引)
// 函数返回: 捕获值
////////////////////////////////////////
uint16_t HSPWM_ReadCapture(uint8_t PWMx)
{
uint16_t cap;
switch (PWMx)
{
case PWMA_CH1:cap = HSPWMA_ReadCCR1Value(); break;
case PWMA_CH2:cap = HSPWMA_ReadCCR2Value(); break;
case PWMA_CH3:cap = HSPWMA_ReadCCR3Value(); break;
case PWMA_CH4:cap = HSPWMA_ReadCCR4Value(); break;
case PWMB_CH5:cap = HSPWMB_ReadCCR5Value(); break;
case PWMB_CH6:cap = HSPWMB_ReadCCR6Value(); break;
case PWMB_CH7:cap = HSPWMB_ReadCCR7Value(); break;
case PWMB_CH8:cap = HSPWMB_ReadCCR8Value(); break;
default: cap = 0;
}
return cap;
}
////////////////////////////////////////
// 异步方式读取PWMA特殊功能寄存器
// 入口参数: addr: (PWMA特殊功能寄存器的低7位)
// 函数返回: 寄存器的值
////////////////////////////////////////;
uint8_t HSPWMA_ReadReg(uint8_t addr)
{
uint8_t dat;
while (HSPWMA_CheckBusy()); //等待前一个异步读写完成
HSPWMA_AsyncRead(addr, dat); //触发异步方式读取寄存器
return dat;
}
////////////////////////////////////////
// 异步方式写PWMA特殊功能寄存器
// 入口参数: addr: (PWMA特殊功能寄存器的低7位)
// dat: (待写入的数据)
// 函数返回: 无
////////////////////////////////////////;
void HSPWMA_WriteReg(uint8_t addr, uint8_t dat)
{
while (HSPWMA_CheckBusy()); //等待前一个异步读写完成
HSPWMA_AsyncWrite(addr, dat); //触发异步方式写寄存器
}
////////////////////////////////////////
// 异步方式读取PWMB特殊功能寄存器
// 入口参数: addr: (PWMB特殊功能寄存器的低7位)
// 函数返回: 寄存器的值
////////////////////////////////////////;
uint8_t HSPWMB_ReadReg(uint8_t addr)
{
uint8_t dat;
while (HSPWMB_CheckBusy()); //等待前一个异步读写完成
HSPWMB_AsyncRead(addr, dat); //触发异步方式读取寄存器
return dat;
}
////////////////////////////////////////
// 异步方式写PWMB特殊功能寄存器
// 入口参数: addr: (PWMB特殊功能寄存器的低7位)
// dat: (待写入的数据)
// 函数返回: 无
////////////////////////////////////////;
void HSPWMB_WriteReg(uint8_t addr, uint8_t dat)
{
while (HSPWMB_CheckBusy()); //等待前一个异步读写完成
HSPWMB_AsyncWrite(addr, dat); //触发异步方式写寄存器
}
////////////////////////////////////////
// USB库初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_Init(void)
{
usb_init(); //初始化USB模块
USB_SetIntPriority(0); //设置中断为最低优先级
set_usb_ispcmd("@STCISP#"); //设置USB不停电下载命令
//<<AICUBE_USER_USBLIB_INITIAL_BEGIN>>
// 在此添加用户初始化代码
//<<AICUBE_USER_USBLIB_INITIAL_END>>
}
////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
while (DeviceState != DEVSTATE_CONFIGURED) //等待USB完成配置
WDT_Clear(); //清看门狗定时器 (防止硬件自动使能看门狗)
}
////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
if (bUsbOutReady) //查询是否有接收到USB主机发送数据
{
//<<AICUBE_USER_USBLIB_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
USB_SendData(UsbOutBuffer, OutNumber); // 原路返回, 用于测试
// 在此处添加用户处理接收数据的代码
//<<AICUBE_USER_USBLIB_ISR_CODE1_END>>
usb_OUT_done(); //当前包的数据处理完成,通知USB主机可以发送下一包数据
}
}
////////////////////////////////////////
// 定时器0中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_ISR(void) interrupt TMR0_VECTOR
{
//<<AICUBE_USER_TIMER0_ISR_CODE1_BEGIN>>
// 在此添加中断函数用户代码
if (!PWM1_Flag)
{
PWM1_Duty++;
if (PWM1_Duty > PWM_PERIOD)
PWM1_Flag = 1;
}
else
{
PWM1_Duty--;
if (PWM1_Duty <= 0)
PWM1_Flag = 0;
}
if (!PWM2_Flag)
{
PWM2_Duty++;
if (PWM2_Duty > PWM_PERIOD)
PWM2_Flag = 1;
}
else
{
PWM2_Duty--;
if (PWM2_Duty <= 0)
PWM2_Flag = 0;
}
if (!PWM3_Flag)
{
PWM3_Duty++;
if (PWM3_Duty > PWM_PERIOD)
PWM3_Flag = 1;
}
else
{
PWM3_Duty--;
if (PWM3_Duty <= 0)
PWM3_Flag = 0;
}
if (!PWM4_Flag)
{
PWM4_Duty++;
if (PWM4_Duty > PWM_PERIOD)
PWM4_Flag = 1;
}
else
{
PWM4_Duty--;
if (PWM4_Duty <= 0)
PWM4_Flag = 0;
}
UpdatePwm();
//<<AICUBE_USER_TIMER0_ISR_CODE1_END>>
}
//<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
// 在此添加用户函数实现代码
//========================================================================
// 函数: UpdatePwm(void)
// 描述: 更新PWM占空比.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void UpdatePwm(void)
{
PWM_UpdateDuty(PWMA_CH1, PWM1_Duty);
PWM_UpdateDuty(PWMA_CH2, PWM2_Duty);
PWM_UpdateDuty(PWMA_CH3, PWM3_Duty);
PWM_UpdateDuty(PWMA_CH4, PWM4_Duty);
}
//<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>