CListery 发表于 2025-11-5 16:06:02

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; // 中断方式读取比较器比较结果
}

CListery 发表于 2025-11-6 17:29:47

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();
}

CListery 发表于 2025-11-7 10:01:42

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();
}

芯Skye 发表于 2025-11-7 10:28:39

推荐优先看的 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

CListery 发表于 2025-11-7 17:15:01

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(); // 读暂存存储器命令
}

CListery 发表于 2025-11-12 11:11:16

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;
}

CListery 发表于 2025-11-12 16:28:19

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;
}

CListery 发表于 2025-11-19 14:06:58

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;
    }
}



CListery 发表于 2025-11-21 14:02:42

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();
}

CListery 发表于 2025-11-24 16:58:32

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>>


页: 1 2 3 4 [5] 6
查看完整版本: 跟着冲哥学习单片机