找回密码
 立即注册
楼主: CListery

跟着冲哥学习单片机

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-7 10:01:42 | 显示全部楼层
39. DS18B20

  1. #include "pref.h"
  2. #include "digital_display.h"
  3. #include "timer.h"
  4. #include "ntc.h"
  5. #include "bee.h"
  6. #include <STDIO.H>
  7. #include "cmp.h"
  8. #include "internal_eeprom.h"
  9. #include "ds18b20.h"
  10. bit B_1ms; // 1ms标志
  11. u16 msecond;
  12. void sys_init();
  13. void init_usb();
  14. void main()
  15. {
  16.     u16 temp;
  17.     u8 digital_display_pos[8] = {DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK};
  18.     sys_init();
  19.     init_time0();
  20.     digital_display_init();
  21.     init_usb();
  22.     EA = 1; // 打开总中断
  23.     // (12*32768*WDT_PS) / MAIN_Fosc
  24.     // WDT_PS = 128
  25.     // 24M 系统时钟,看门狗计数器溢出时间大概为 2秒
  26.     WDT_CONTR = 0x26;
  27.     while (1)
  28.     {
  29.         WDT_CONTR = 0x36;
  30.         if (B_1ms)
  31.         {
  32.             B_1ms = 0;
  33.             if (++msecond >= 300)
  34.             {
  35.                 msecond = 0;
  36.                 temp = ds18b20_read_temperature();
  37.                
  38.                 if(ds18b20_is_minus())
  39.                 {
  40.                     if(temp > 999)
  41.                     {
  42.                         digital_display_pos[3] = DIS_;
  43.                         digital_display_pos[4] = temp / 1000;
  44.                     }
  45.                     else
  46.                     {
  47.                         digital_display_pos[3] = DIS_BLACK;
  48.                         digital_display_pos[4] = DIS_;
  49.                     }
  50.                 }
  51.                 else
  52.                 {
  53.                     digital_display_pos[3] = DIS_BLACK;
  54.                     if(temp > 999)
  55.                     {
  56.                         digital_display_pos[4] = temp / 1000;
  57.                     }
  58.                     else
  59.                     {
  60.                         digital_display_pos[4] = DIS_BLACK;
  61.                     }
  62.                 }
  63.                 digital_display_pos[5] = (temp % 1000) / 100;
  64.                 digital_display_pos[6] = ((temp % 100) / 10) + DIS_DOT;
  65.                 digital_display_pos[7] = temp % 10;
  66.                 digital_display_set_pos(
  67.                     digital_display_pos[0],
  68.                     digital_display_pos[1],
  69.                     digital_display_pos[2],
  70.                     digital_display_pos[3],
  71.                     digital_display_pos[4],
  72.                     digital_display_pos[5],
  73.                     digital_display_pos[6],
  74.                     digital_display_pos[7]
  75.                 );
  76.             }
  77.         }
  78.     }
  79. }
  80. void sys_init()
  81. {
  82.     WTST = 0;  // 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  83.     EAXFR = 1; // 扩展寄存器(XFR)访问使能
  84.     CKCON = 0; // 提高访问XRAM速度
  85.     {
  86.         P0M1 = 0x30;
  87.         P0M0 = 0x30; // 设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
  88.         P1M1 = 0x30;
  89.         P1M0 = 0x30; // 设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
  90.         P2M1 = 0x3c;
  91.         P2M0 = 0x3c; // 设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
  92.         P3M1 = 0x50;
  93.         P3M0 = 0x50; // 设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
  94.         P4M1 = 0x3c;
  95.         P4M0 = 0x3c; // 设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
  96.         P5M1 = 0x0c;
  97.         P5M0 = 0x0c; // 设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
  98.         P6M1 = 0xff;
  99.         P6M0 = 0xff; // 设置为漏极开路(实验箱加了上拉电阻到3.3V)
  100.         P7M1 = 0x00;
  101.         P7M0 = 0x00; // 设置为准双向口
  102.     }
  103. }
  104. void init_usb()
  105. {
  106.     P3M0 &= ~0x03; // P30,P31 和 USB 的 D-,D+ 共用 PIN 脚
  107.     P3M1 |= 0x03;  // 需要将 P30,P31 设置为高阻输入模式
  108.     IRC48MCR = 0x80; // 使能内部 48M 的 USB 专用 IRC
  109.     while (!(IRC48MCR & 0x01))
  110.         ; // 等待震荡源稳定
  111.     USBCLK = 0x00; // 设置 USB 时钟源为内部 48M 的 USB 专用 IRC
  112.     USBCON = 0x09; // 使能 USB 功能
  113.     usb_init(); // 调用 USB CDC 初始化库函数
  114.     EUSB = 1; // 使能 USB 中断
  115. }
  116. /********************** Timer0 1ms中断函数 ************************/
  117. void timer0(void) interrupt 1
  118. {
  119.     B_1ms = 1;     // 1ms标志
  120.     DisplayScan(); // 1ms扫描显示一位
  121.     bee_on_1ms();
  122. }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:67
  • 最近打卡:2026-02-10 13:19:40

22

主题

89

回帖

913

积分

版主

积分
913
发表于 2025-11-7 10:28:39 | 显示全部楼层
推荐优先看的 printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-7 17:15:01 | 显示全部楼层
39. DS18b20 功能扩展

  1. #include "pref.h"
  2. #include "digital_display.h"
  3. #include "timer.h"
  4. #include "ntc.h"
  5. #include "bee.h"
  6. #include <STDIO.H>
  7. #include "cmp.h"
  8. #include "internal_eeprom.h"
  9. #include "ds18b20.h"
  10. bit B_1ms; // 1ms标志
  11. u16 msecond;
  12. void sys_init();
  13. void init_usb();
  14. void main()
  15. {
  16.     u16 temp;
  17.     u8 digital_display_pos[8] = {DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK, DIS_BLACK};
  18.     u8 serial[8];
  19.     u8 config[5];
  20.     sys_init();
  21.     init_time0();
  22.     digital_display_init();
  23.     init_usb();
  24.     EA = 1; // 打开总中断
  25.     ds18b20_read_serial(serial);
  26.     ds18b20_read_cfg(serial, config);
  27.     // 接收任意串口数据后继续执行, 方便调试
  28.     while (!bUsbOutReady)
  29.         ;
  30.     printf_usb("\r\nserial: %X %X %X %X %X %X %X %X\r\n", serial[7], serial[6], serial[5], serial[4], serial[3], serial[2], serial[1], serial[0]);
  31.     printf_usb("\r\nconfig: %X %X %X %X %X\r\n", config[4], config[3], config[2], config[1], config[0]);
  32.     digital_display_black();
  33.     // (12*32768*WDT_PS) / MAIN_Fosc
  34.     // WDT_PS = 128
  35.     // 24M 系统时钟,看门狗计数器溢出时间大概为 2秒
  36.     WDT_CONTR = 0x26;
  37.     while (1)
  38.     {
  39.         WDT_CONTR = 0x36;
  40.         if (B_1ms)
  41.         {
  42.             B_1ms = 0;
  43.             if (++msecond >= 500)
  44.             {
  45.                 msecond = 0;
  46.                 temp = ds18b20_read_temperature_target(serial);
  47.                 printf_usb("%0.2f", ((float)temp / 100));
  48.                 if (ds18b20_is_minus())
  49.                 {
  50.                     if (temp > 999)
  51.                     {
  52.                         digital_display_pos[3] = DIS_;
  53.                         digital_display_pos[4] = temp / 1000;
  54.                     }
  55.                     else
  56.                     {
  57.                         digital_display_pos[3] = DIS_BLACK;
  58.                         digital_display_pos[4] = DIS_;
  59.                     }
  60.                 }
  61.                 else
  62.                 {
  63.                     digital_display_pos[3] = DIS_BLACK;
  64.                     if (temp > 999)
  65.                     {
  66.                         digital_display_pos[4] = temp / 1000;
  67.                     }
  68.                     else
  69.                     {
  70.                         digital_display_pos[4] = DIS_BLACK;
  71.                     }
  72.                 }
  73.                 digital_display_pos[5] = (temp % 1000) / 100 + DIS_DOT;
  74.                 digital_display_pos[6] = ((temp % 100) / 10);
  75.                 digital_display_pos[7] = temp % 10;
  76.                 digital_display_set_pos(
  77.                     digital_display_pos[0],
  78.                     digital_display_pos[1],
  79.                     digital_display_pos[2],
  80.                     digital_display_pos[3],
  81.                     digital_display_pos[4],
  82.                     digital_display_pos[5],
  83.                     digital_display_pos[6],
  84.                     digital_display_pos[7]);
  85.                 usb_OUT_done();
  86.             }
  87.             if (!P34)
  88.             {
  89.                 // 精度切换
  90.                 delay_ms(100);
  91.                 if (!P34)
  92.                 {
  93.                     digital_display_set(12345678);
  94.                     temp = (config[2] & 0x60) >> 5;
  95.                     if (temp >= 3)
  96.                     {
  97.                         temp = 0;
  98.                     }
  99.                     else
  100.                     {
  101.                         temp++;
  102.                     }
  103.                     ds18b20_cfg_ratio(serial, temp);
  104.                     ds18b20_read_cfg(serial, config);
  105.                     printf_usb("\r\nconfig: %X %X %X %X %X\r\n", config[4], config[3], config[2], config[1], config[0]);
  106.                     while (!P34)
  107.                     {
  108.                         WDT_CONTR = 0x36;
  109.                     }
  110.                     digital_display_black();
  111.                 }
  112.             }
  113.         }
  114.     }
  115. }
  116. void sys_init()
  117. {
  118.     WTST = 0;  // 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  119.     EAXFR = 1; // 扩展寄存器(XFR)访问使能
  120.     CKCON = 0; // 提高访问XRAM速度
  121.     {
  122.         P0M1 = 0x30;
  123.         P0M0 = 0x30; // 设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
  124.         P1M1 = 0x30;
  125.         P1M0 = 0x30; // 设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
  126.         P2M1 = 0x3c;
  127.         P2M0 = 0x3c; // 设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
  128.         P3M1 = 0x50;
  129.         P3M0 = 0x50; // 设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
  130.         P4M1 = 0x3c;
  131.         P4M0 = 0x3c; // 设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
  132.         P5M1 = 0x0c;
  133.         P5M0 = 0x0c; // 设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
  134.         P6M1 = 0xff;
  135.         P6M0 = 0xff; // 设置为漏极开路(实验箱加了上拉电阻到3.3V)
  136.         P7M1 = 0x00;
  137.         P7M0 = 0x00; // 设置为准双向口
  138.     }
  139. }
  140. void init_usb()
  141. {
  142.     P3M0 &= ~0x03; // P30,P31 和 USB 的 D-,D+ 共用 PIN 脚
  143.     P3M1 |= 0x03;  // 需要将 P30,P31 设置为高阻输入模式
  144.     IRC48MCR = 0x80; // 使能内部 48M 的 USB 专用 IRC
  145.     while (!(IRC48MCR & 0x01))
  146.         ; // 等待震荡源稳定
  147.     USBCLK = 0x00; // 设置 USB 时钟源为内部 48M 的 USB 专用 IRC
  148.     USBCON = 0x09; // 使能 USB 功能
  149.     usb_init(); // 调用 USB CDC 初始化库函数
  150.     EUSB = 1; // 使能 USB 中断
  151. }
  152. /********************** Timer0 1ms中断函数 ************************/
  153. void timer0(void) interrupt 1
  154. {
  155.     B_1ms = 1;     // 1ms标志
  156.     DisplayScan(); // 1ms扫描显示一位
  157.     bee_on_1ms();
  158. }
复制代码

  1. #include "ds18b20.h"
  2. sbit DQ = P3 ^ 3; // DS18B20的数据口
  3. bit _MinusFlag;   // 负数标志,0:正数,1:负数
  4. bit ds18b20_is_minus()
  5. {
  6.     return _MinusFlag;
  7. }
  8. void ds18b20_read_scratchpad(u8 *temperature, u8 *tHL, u8 *cfg, u8 *user, u8 *crc)
  9. {
  10.     ds18b20_writebyte(0xBE); // 读取暂存器
  11.     temperature[0] = ds18b20_readbyte(); // 读温度低字节
  12.     temperature[1] = ds18b20_readbyte(); // 读温度高字节
  13.     tHL[0] = ds18b20_readbyte(); // T_H Reg
  14.     tHL[1] = ds18b20_readbyte(); // T_L Reg
  15.     *cfg = ds18b20_readbyte(); // Config Reg
  16.     ds18b20_readbyte(); // FFh
  17.     user[0] = ds18b20_readbyte(); // User byte
  18.     user[1] = ds18b20_readbyte(); // User byte
  19.     *crc = ds18b20_readbyte();
  20. }
  21. void ds18b20_write_scratchpad(u8 *config)
  22. {
  23.     ds18b20_writebyte(0x4E); // 写入暂存器
  24.     ds18b20_writebyte(config[0]);
  25.     ds18b20_writebyte(config[1]);
  26.     ds18b20_writebyte(config[2]);
  27.     ds18b20_reset();
  28. }
  29. void ds18b20_write_eeprom(u8 *serial)
  30. {
  31.     ds18b20_reset();
  32.     ds18b20_match_serial(serial);
  33.     ds18b20_writebyte(0x48); // 写入EEPROM
  34.     while (!DQ)
  35.         ;
  36. }
  37. u16 ds18b20_read_tempturature()
  38. {
  39.     u16 Temperature;
  40.     u8 temp[2];
  41.     ds18b20_read_scratchpad(temp, 0, 0, 0, 0);
  42.     if (temp[1] & 0xf8) // 判断是否位负数
  43.     {
  44.         _MinusFlag = 1; // 设置负数标志
  45.         Temperature = (temp[1] << 8) | temp[0];
  46.         Temperature = ~Temperature + 1;
  47.         Temperature *= 0.625; // 0.0625 * 10,保留1位小数点
  48.     }
  49.     else
  50.     {
  51.         _MinusFlag = 0;                                    // 清除负数标志
  52.         Temperature = (((temp[1] << 8) | temp[0]) * 6.25); // 0.0625 * 100,保留2位小数点
  53.     }
  54.     return Temperature;
  55. }
  56. void ds18b20_reset()
  57. {
  58.     CY = 1;
  59.     while (CY)
  60.     {
  61.         DQ = 0;        // 送出低电平复位信号
  62.         delay_us(240); // 延时至少480us
  63.         delay_us(240);
  64.         DQ = 1;        // 释放数据线
  65.         delay_us(60);  // 等待60us
  66.         CY = DQ;       // 检测存在脉冲
  67.         delay_us(240); // 等待设备释放数据线
  68.         delay_us(180);
  69.     }
  70. }
  71. void ds18b20_read_serial(u8 *dat)
  72. {
  73.     u8 i, j, tmp_u8;
  74.     bit tmp_bit;
  75.     ds18b20_reset();
  76.     ds18b20_writebyte(0xF0); // Search ROM
  77.     for (i = 0; i < 8; i++)
  78.     {
  79.         tmp_u8 = 0;
  80.         for (j = 0; j < 8; j++)
  81.         {
  82.             tmp_bit = ds18b20_readbit();         // B20 TX bit
  83.             while (ds18b20_readbit() == tmp_bit) // B20 TX !bit
  84.                 ;
  85.             ds18b20_writebit(tmp_bit); // Master TX bit
  86.             // printf_usb("%d", tmp_bit);
  87.             tmp_u8 >>= 1;
  88.             if (tmp_bit)
  89.             {
  90.                 tmp_u8 |= 0x80;
  91.             }
  92.         }
  93.         *dat++ = tmp_u8;
  94.     }
  95. }
  96. void ds18b20_match_serial(u8 *dat)
  97. {
  98.     u8 i, j, tmp_u8;
  99.     ds18b20_reset();
  100.     ds18b20_writebyte(0x55); // Match ROM
  101.     for (i = 0; i < 8; i++)
  102.     {
  103.         tmp_u8 = dat[i];
  104.         for (j = 0; j < 8; j++)
  105.         {
  106.             ds18b20_writebit(tmp_u8 & 0x01); // Master TX bit
  107.             tmp_u8 >>= 1;
  108.         }
  109.     }
  110. }
  111. void ds18b20_writebit(bit b)
  112. {
  113.     DQ = 0;      // 开始时间片
  114.     delay_us(1); // 延时等待
  115.     DQ = b;
  116.     delay_us(60); // 等待时间片结束
  117.     DQ = 1;       // 恢复数据线
  118.     delay_us(1);  // 恢复延时
  119. }
  120. void ds18b20_writebyte(u8 dat)
  121. {
  122.     char i;
  123.     for (i = 0; i < 8; i++) // 8位计数器
  124.     {
  125.         DQ = 0;      // 开始时间片
  126.         delay_us(1); // 延时等待
  127.         dat >>= 1;   // 送出数据
  128.         DQ = CY;
  129.         delay_us(60); // 等待时间片结束
  130.         DQ = 1;       // 恢复数据线
  131.         delay_us(1);  // 恢复延时
  132.     }
  133. }
  134. bit ds18b20_readbit()
  135. {
  136.     bit i;
  137.     DQ = 0;      // 开始时间片
  138.     delay_us(1); // 延时等待
  139.     DQ = 1;      // 准备接收
  140.     delay_us(1); // 接收延时
  141.     i = DQ;
  142.     delay_us(60); // 等待时间片结束
  143.     return i;
  144. }
  145. u8 ds18b20_readbyte()
  146. {
  147.     u8 i;
  148.     u8 dat = 0;
  149.     for (i = 0; i < 8; i++) // 8位计数器
  150.     {
  151.         dat >>= 1;
  152.         DQ = 0;      // 开始时间片
  153.         delay_us(1); // 延时等待
  154.         DQ = 1;      // 准备接收
  155.         delay_us(1); // 接收延时
  156.         if (DQ)
  157.             dat |= 0x80; // 读取数据
  158.         delay_us(60);    // 等待时间片结束
  159.     }
  160.     return dat;
  161. }
  162. void ds18b20_read_cfg(u8 *serial, u8 *cfg)
  163. {
  164.     u8 t_threshold[2], _user[2];
  165.     u8 _config;
  166.     ds18b20_reset();
  167.     ds18b20_match_serial(serial);
  168.     ds18b20_read_scratchpad(0, t_threshold, &_config, _user, 0);
  169.     cfg[0] = t_threshold[0];
  170.     cfg[1] = t_threshold[1];
  171.     cfg[2] = _config;
  172.     cfg[3] = _user[0];
  173.     cfg[4] = _user[1];
  174. }
  175. /**
  176. * 0 - 0.5
  177. * 1 - 0.25
  178. * 2 - 0.125
  179. * 3 - 0.0625
  180. */
  181. void ds18b20_cfg_ratio(u8 *serial, u8 ratio)
  182. {
  183.     u8 config[5];
  184.     ds18b20_read_cfg(serial, config);
  185.     config[2] = ratio << 5;
  186.     ds18b20_reset();
  187.     ds18b20_match_serial(serial);
  188.     ds18b20_write_scratchpad(config);
  189.     ds18b20_write_eeprom(serial);
  190. }
  191. u16 ds18b20_read_temperature_target(u8 *serial)
  192. {
  193.     ds18b20_match_serial(serial); // 找指定设备
  194.     ds18b20_writebyte(0x44);      // 写入转换命令
  195.     while (!DQ)
  196.         ; // 等待转换完成
  197.     ds18b20_reset();              // 复位
  198.     ds18b20_match_serial(serial); // 找指定设备
  199.     return ds18b20_read_tempturature();
  200. }
  201. u16 ds18b20_read_temperature_any()
  202. {
  203.     ds18b20_reset();         // 设备复位
  204.     ds18b20_writebyte(0xCC); // 跳过ROM命令
  205.     ds18b20_writebyte(0x44); // 开始转换命令
  206.     while (!DQ)
  207.         ; // 等待转换完成
  208.     ds18b20_reset();                    // 设备复位
  209.     ds18b20_writebyte(0xCC);            // 跳过ROM命令
  210.     return ds18b20_read_tempturature(); // 读暂存存储器命令
  211. }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-12 11:11:16 | 显示全部楼层
41. 软件模拟SPI

main.c
  1.                 spi_flash_writebyte(0xAB);
  2.                 // 3个字节无效数据
  3.                 spi_flash_readbyte();
  4.                 spi_flash_readbyte();
  5.                 spi_flash_readbyte();
  6.                 // 在 CS 拉高之前,flash会一直输出device id
  7.                 printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
  8.                 printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
  9.                 printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
  10.                 printf_usb("device id: 0x%X\r\n", spi_flash_readbyte());
  11.                 spi_flash_disable();
  12.                 spi_flash_writebyte(0x9F);
  13.                 printf_usb("JEDEC ID: ");
  14.                 printf_usb("%X ", spi_flash_readbyte());
  15.                 printf_usb("%X ", spi_flash_readbyte());
  16.                 printf_usb("%X \r\n", spi_flash_readbyte());
  17.                 spi_flash_disable();
  18.                 spi_flash_writebyte(0x4B);
  19.                 // 4个字节无效数据
  20.                 spi_flash_readbyte();
  21.                 spi_flash_readbyte();
  22.                 spi_flash_readbyte();
  23.                 spi_flash_readbyte();
  24.                 printf_usb("UniqueID: ");
  25.                 // 64位序列号
  26.                 printf_usb("%X ", spi_flash_readbyte());
  27.                 printf_usb("%X ", spi_flash_readbyte());
  28.                 printf_usb("%X ", spi_flash_readbyte());
  29.                 printf_usb("%X ", spi_flash_readbyte());
  30.                 printf_usb("%X ", spi_flash_readbyte());
  31.                 printf_usb("%X ", spi_flash_readbyte());
  32.                 printf_usb("%X ", spi_flash_readbyte());
  33.                 printf_usb("%X \r\n", spi_flash_readbyte());
  34.                 spi_flash_disable();
复制代码


spi.c
  1. #define SCLK P25
  2. #define MISO P24
  3. #define MOSI P23
  4. #define CS P22
  5. #define WP P53
  6. void spi_flash_reset()
  7. {
  8.     SCLK = 0;
  9.     WP = 1;
  10.     MISO = 1;
  11.     MOSI = 1;
  12.     CS = 0;
  13. }
  14. void spi_flash_disable()
  15. {
  16.     CS = 1;
  17. }
  18. void spi_flash_writebyte(u8 dat)
  19. {
  20.     u8 i;
  21.     spi_flash_reset();
  22.     for (i = 0; i < 8; i++)
  23.     {
  24.         if (dat & 0x80)
  25.         {
  26.             MOSI = 1;
  27.         }
  28.         else
  29.         {
  30.             MOSI = 0;
  31.         }
  32.         SCLK = 0;
  33.         SCLK = 1;
  34.         dat <<= 1;
  35.     }
  36. }
  37. u8 spi_flash_readbyte()
  38. {
  39.     u8 dat, i;
  40.     spi_flash_reset();
  41.     for (i = 0; i < 8; i++)
  42.     {
  43.         dat <<= 1;
  44.         SCLK = 0;
  45.         SCLK = 1;
  46.         dat |= MISO;
  47.     }
  48.     return dat;
  49. }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-12 16:28:19 | 显示全部楼层
42. 硬件SPI

SPI
  1. #include "spi_flash.h"
  2. #define CS P22
  3. #define MOSI P23
  4. #define MISO P24
  5. #define SCLK P25
  6. #define WP P53
  7. void init_spi_flash()
  8. {
  9.     P_SW1 &= 0xF3;  // 清除 SPI 功能脚选择位
  10.     P_SW1 |= 0x04;  // SS=P22 MOSI=P23 MISO=P24 SCLK=P25
  11.     SPSTAT = 0xC0;  // 清除 SPI 状态寄存器
  12.     SSIG = 1;   // 忽略 SS 引脚功能,使用 MSTR 确定主、从
  13.     DORD = 0;   // 从最高位开始传输 SPI 数据
  14.     MSTR = 1;   // 主机模式
  15.     CPOL = 1;   // SCLK 空闲为高电平,前时钟沿为下降沿
  16.     CPHA = 1;   // 数据在 SCLK 的前时钟沿驱动,后时钟沿采样
  17.     SPR1 = 0;   // SPI 时钟频率
  18.     SPR0 = 0;   //      SPI 输入时钟/4
  19.     SPEN = 1;   // 使能 SPI
  20. }
  21. void spi_flash_enable()
  22. {
  23.     CS = 0;
  24. }
  25. void spi_flash_disable()
  26. {
  27.     CS = 1;
  28. }
  29. void spi_flash_writebyte(u8 dat)
  30. {
  31.     SPDAT = dat;
  32.     while(SPIF == 0);
  33.     SPIF = 1;
  34.     WCOL = 1;
  35. }
  36. u8 spi_flash_readbyte()
  37. {
  38.     SPDAT = 0xFF;
  39.     while(SPIF == 0);
  40.     SPIF = 1;
  41.     WCOL = 1;
  42.     return (SPDAT);
  43. }
复制代码



USART2-SPI
  1. #include "spi_flash.h"
  2. #define CS P22
  3. #define MOSI P23
  4. #define MISO P24
  5. #define SCLK P25
  6. #define WP P53
  7. void init_spi_flash()
  8. {
  9.     S2SPI_S1 = 0;
  10.     S2SPI_S0 = 1;
  11.     S2SM0 = 0;
  12.     S2SM1 = 0;
  13.     S2REN = 1;
  14.     USART2CR1 = 0x10;
  15.     USART2CR4 = 0x00;
  16.     USART2CR1 |= 0x08;
  17.     S2TI = 0;
  18.     S2RI = 0;
  19. }
  20. void spi_flash_enable()
  21. {
  22.     CS = 0;
  23. }
  24. void spi_flash_disable()
  25. {
  26.     CS = 1;
  27. }
  28. void spi_flash_writebyte(u8 dat)
  29. {
  30.     S2TI = 0;
  31.     S2BUF = dat;
  32.     while (!S2TI)
  33.         ;
  34. }
  35. u8 spi_flash_readbyte()
  36. {
  37.     S2TI = 0;
  38.     S2BUF = 0xFF;
  39.     while (!S2TI)
  40.         ;
  41.     return S2BUF;
  42. }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-19 14:06:58 | 显示全部楼层
43. SPI 读写 FLASH 芯片

读取device id
读取 jedec id
读取 unique id
记录开关机次数

  1.             printf_usb("device ID: 0x%X\r\n", spi_flash_load_DEVICE_ID());
  2.             printf_usb("JEDEC ID: %lX\r\n", spi_flash_load_JEDEC_ID());
  3.             spi_flash_load_UNIQUE_ID(tmp);
  4.             printf_usb("Unique ID: %lX%lX\n", tmp[1], tmp[0]);
  5.             printf_usb("busy: %d\r\n", spi_flash_check_busy());
  6.             spi_flash_read(DAT_ADDR, buf, 2);
  7.             printf_usb("%X %d\r\n", buf[0], buf[1]);
  8.             if (buf[0] == 0x8F)
  9.             {
  10.                 printf_usb("found data\r\n");
  11.                 spi_flash_erase(DAT_ADDR);
  12.                 buf[1]++;
  13.             }
  14.             else
  15.             {
  16.                 printf_usb("erase page\r\n");
  17.                 spi_flash_erase(DAT_ADDR);
  18.                 buf[0] = 0x8F;
  19.                 buf[1] = 1;
  20.             }
  21.             spi_flash_write(DAT_ADDR, buf, 2);
  22.             printf_usb("%X %d\r\n", buf[0], buf[1]);
  23.             digital_display_set(buf[1]);
  24.             
  25.             usb_OUT_done();
复制代码

NTC采集温度并存储最近10次温度数值存储到flash芯片
  1. void clear_temperature()
  2. {
  3.     spi_flash_erase(DAT_ADDR);
  4.     printf_usb("CLEAR TEMPERATURE DATA!");
  5. }
  6. void print_temperature(u8 *buf, u8 cnt)
  7. {
  8.     u8 i;
  9.     u16 tmp_u16;
  10.     printf_usb(">>>>>>>>>>>>>>>>>>>>>>\r\n");
  11.     printf_usb("TEMPERTURE DATA:\r\n");
  12.     for (i = 1; i <= cnt; i++)
  13.     {
  14.         // 高8位地址
  15.         tmp_u16 = buf[(i * 2 + 1)] << 8;
  16.         // 低8位地址
  17.         tmp_u16 |= buf[(i * 2)];
  18.         if (tmp_u16 >= 400)
  19.             F0 = 0, tmp_u16 -= 400; // 温度 >= 0度
  20.         else
  21.             F0 = 1, tmp_u16 = 400 - tmp_u16; // 温度 <  0度
  22.         printf_usb("%2d :  %5.1f\r\n", i, ((float)tmp_u16) / 10);
  23.     }
  24.     printf_usb("<<<<<<<<<<<<<<<<<<<<<<\r\n");
  25. }
  26. void refresh_temperature(BOOL is_print)
  27. {
  28.     // W25X40CL
  29.     // 1K = 512byte * 2 = 1024byte
  30.     // 4KB = 4096byte
  31.     // 1页 = 256byte
  32.     // 4KB = 16页
  33.     // 地址格式(24 位):A23 A22 ... A8 A7 A6 ... A0
  34.     // 高 16 位(A23~A8):决定 “哪一页”(比如 A23~A8=0000h,就是第 0 页;A23~A8=0001h,就是第 1 页);
  35.     // 低 8 位(A7~A0):决定 “页内的哪个字节”(00h~FFh,对应页内第 0 字节到第 255 字节)。
  36.     u8 buf[22], cnt_temperature, flag; // temperture_9, temperture_8, ... , temperture_0, count, flag
  37.     u8 i, tmp_H, tmp_L;
  38.     u16 tmp_u16;
  39.     spi_flash_read(DAT_ADDR, buf, 22);
  40.     printf_usb("read  buf: 0x%X  %d\r\n", buf[0], buf[1]);
  41.     flag = buf[0];
  42.     if (flag == 0x80)
  43.     {
  44.         cnt_temperature = buf[1];
  45.     }
  46.     else
  47.     {
  48.         cnt_temperature = 1;
  49.     }
  50.     if (is_print)
  51.     {
  52.         if (flag == 0x80)
  53.         {
  54.             print_temperature(buf, cnt_temperature);
  55.             return;
  56.         }
  57.         else
  58.         {
  59.             printf_usb("not found temperture data");
  60.             return;
  61.         }
  62.     }
  63.     if (cnt_temperature >= MAX_TEMP_COUNT)
  64.     {
  65.         cnt_temperature = MAX_TEMP_COUNT;
  66.         // 滚动记录
  67.         for (i = 1; i < MAX_TEMP_COUNT; i++)
  68.         {
  69.             buf[i * 2] = buf[(i + 1) * 2];
  70.             buf[i * 2 + 1] = buf[(i + 1) * 2 + 1];
  71.         }
  72.     }
  73.     tmp_u16 = Get_ADC12bitResult(ADC_CHANNEL_NTC);
  74.     printf_usb("adc: %d\r\n", tmp_u16);
  75.     if (tmp_u16 < 4096)
  76.     {
  77.         if (flag == 0x80 && cnt_temperature < MAX_TEMP_COUNT)
  78.         {
  79.             cnt_temperature += 1;
  80.         }
  81.         tmp_u16 = get_temperature(tmp_u16);
  82.         tmp_H = (u8)(tmp_u16 >> 8);
  83.         tmp_L = (u8)(tmp_u16 & 0xFF);
  84.         // 高8位地址
  85.         buf[(cnt_temperature * 2 + 1)] = tmp_H;
  86.         // 低8位地址
  87.         buf[(cnt_temperature * 2)] = tmp_L;
  88.         buf[0] = 0x80;
  89.         buf[1] = cnt_temperature;
  90.         spi_flash_erase(DAT_ADDR);
  91.         printf_usb("write  buf: 0x%X  %d\r\n", buf[0], buf[1]);
  92.         spi_flash_write(DAT_ADDR, buf, 22);
  93.     }
  94.     else
  95.     {
  96.         printf_usb("invalid adc data, skip sample");
  97.         return;
  98.     }
  99. }
复制代码



回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-21 14:02:42 | 显示全部楼层
47. USB-CDC串口读写 FLASH

读取FLASH芯片地址

  1. u8 i2c_24Cxx_load_device_addr()
  2. {
  3.   u8 a2a1a0; // A2/A1/A0 地址位,000~111 共有7钟组合
  4.   u8 tmp;
  5.   u8 heigh_addr = 0xA0; // 高位地址固定为 1010
  6.   for (a2a1a0 = 0; a2a1a0 < 8; a2a1a0++)
  7.   {
  8.     tmp = heigh_addr | (a2a1a0 << 1);
  9.     i2c_24Cxx_start();
  10.     if (!i2c_24Cxx_send_byte(tmp & 0xFE)) // 发送器件地址+写选择位
  11.     {
  12.       i2c_24Cxx_stop();
  13.       // 接收到器件 ACK
  14.       printf_usb("device addr: 0x%X\r\n", tmp);
  15.       return tmp;
  16.     }
  17.     i2c_24Cxx_stop();
  18.   }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-24 16:58:32 | 显示全部楼层
50. PWM


  1. //<<AICUBE_USER_HEADER_REMARK_BEGIN>>
  2. ////////////////////////////////////////
  3. // 在此添加用户文件头说明信息
  4. // 文件名称: main.c
  5. // 文件描述:
  6. // 文件版本: V1.0
  7. // 修改记录:
  8. //   1. (2025-11-24) 创建文件
  9. ////////////////////////////////////////
  10. //<<AICUBE_USER_HEADER_REMARK_END>>
  11. #include "config.h"                     //默认已包含stdio.h、intrins.h等头文件
  12. //<<AICUBE_USER_INCLUDE_BEGIN>>
  13. // 在此添加用户头文件包含
  14. //<<AICUBE_USER_INCLUDE_END>>
  15. //<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
  16. // 在此添加用户全局变量定义、用户宏定义以及函数声明
  17. #define PWM_PERIOD 999 // 设置周期值
  18. u16 PWM1_Duty;
  19. u16 PWM2_Duty;
  20. u16 PWM3_Duty;
  21. u16 PWM4_Duty;
  22. bit PWM1_Flag;
  23. bit PWM2_Flag;
  24. bit PWM3_Flag;
  25. bit PWM4_Flag;
  26. void UpdatePwm(void);
  27. //<<AICUBE_USER_GLOBAL_DEFINE_END>>
  28. ////////////////////////////////////////
  29. // 项目主函数
  30. // 入口参数: 无
  31. // 函数返回: 无
  32. ////////////////////////////////////////
  33. void main(void)
  34. {
  35.     //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
  36.     // 在此添加用户主函数初始化代码
  37.     //<<AICUBE_USER_MAIN_INITIAL_END>>
  38.     SYS_Init();
  39.     //<<AICUBE_USER_MAIN_CODE_BEGIN>>
  40.     // 在此添加主函数中运行一次的用户代码
  41.     //<<AICUBE_USER_MAIN_CODE_END>>
  42.     while (1)
  43.     {
  44.         USBLIB_OUT_Done();              //查询方式处理USB接收的数据
  45.         //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
  46.         // 在此添加主函数中用户主循环代码
  47.         //<<AICUBE_USER_MAIN_LOOP_END>>
  48.     }
  49. }
  50. ////////////////////////////////////////
  51. // 系统初始化函数
  52. // 入口参数: 无
  53. // 函数返回: 无
  54. ////////////////////////////////////////
  55. void SYS_Init(void)
  56. {
  57.     EnableAccessXFR();                  //使能访问扩展XFR
  58.     AccessCodeFastest();                //设置最快速度访问程序代码
  59.     AccessIXramFastest();               //设置最快速度访问内部XDATA
  60.     IAP_SetTimeBase();                  //设置IAP等待参数,产生1us时基
  61.     //<<AICUBE_USER_PREINITIAL_CODE_BEGIN>>
  62.     // 在此添加用户预初始化代码
  63.     //<<AICUBE_USER_PREINITIAL_CODE_END>>
  64.     P0M0 = 0x00; P0M1 = 0x00;           //初始化P0口为准双向口模式
  65.     P1M0 = 0x00; P1M1 = 0x00;           //初始化P1口为准双向口模式
  66.     P2M0 = 0x00; P2M1 = 0x00;           //初始化P2口为准双向口模式
  67.     P3M0 = 0x00; P3M1 = 0x00;           //初始化P3口为准双向口模式
  68.     P4M0 = 0x00; P4M1 = 0x00;           //初始化P4口为准双向口模式
  69.     P5M0 = 0x00; P5M1 = 0x00;           //初始化P5口为准双向口模式
  70.     P6M0 = 0x00; P6M1 = 0x00;           //初始化P6口为准双向口模式
  71.     P7M0 = 0x00; P7M1 = 0x00;           //初始化P7口为准双向口模式
  72.     PORT0_Init();                       //P0口初始化
  73.     PORT6_Init();                       //P6口初始化
  74.     PORT7_Init();                       //P7口初始化
  75.     TIMER0_Init();                      //定时器0初始化
  76.     PWMA_Init();                        //高级PWMA初始化
  77.     delay_ms(1);
  78.     USBLIB_Init();                      //USB库初始化
  79.     delay_ms(1);
  80.     //<<AICUBE_USER_INITIAL_CODE_BEGIN>>
  81.     // 在此添加用户初始化代码
  82.     P40 = 0;
  83.     P7 = 0x00;
  84.     PWM1_Duty = 249;
  85.     PWM2_Duty = 249 * 2;
  86.     PWM3_Duty = 249 * 3;
  87.     PWM4_Duty = 249 * 4;
  88.     UpdatePwm();
  89.     //<<AICUBE_USER_INITIAL_CODE_END>>
  90.     EnableGlobalInt();                  //使能全局中断
  91.     USBLIB_WaitConfiged();              //等待USB完成配置
  92. }
  93. ////////////////////////////////////////
  94. // 微秒延时函数
  95. // 入口参数: us (设置延时的微秒值)
  96. // 函数返回: 无
  97. ////////////////////////////////////////
  98. void delay_us(uint16_t us)
  99. {
  100.     do
  101.     {
  102.         NOP(18);                        //(MAIN_Fosc + 500000) / 1000000 - 6
  103.     } while (--us);
  104. }
  105. ////////////////////////////////////////
  106. // 毫秒延时函数
  107. // 入口参数: ms (设置延时的毫秒值)
  108. // 函数返回: 无
  109. ////////////////////////////////////////
  110. void delay_ms(uint16_t ms)
  111. {
  112.     uint16_t i;
  113.     do
  114.     {
  115.         i = MAIN_Fosc / 6000;
  116.         while (--i);
  117.     } while (--ms);
  118. }
  119. ////////////////////////////////////////
  120. // P0口初始化函数
  121. // 入口参数: 无
  122. // 函数返回: 无
  123. ////////////////////////////////////////
  124. void PORT0_Init(void)
  125. {
  126.     SetP0nInitLevelHigh(PIN_ALL);       //设置P0初始化电平
  127.     SetP0nQuasiMode(PIN_ALL);           //设置P0为准双向口模式
  128.     DisableP0nPullUp(PIN_ALL);          //关闭P0内部上拉电阻
  129.     DisableP0nSchmitt(PIN_ALL);         //使能P0施密特触发
  130.     SetP0nSlewRateNormal(PIN_ALL);      //设置P0一般翻转速度
  131.     SetP0nDrivingNormal(PIN_ALL);       //设置P0一般驱动能力
  132.     SetP0nDigitalInput(PIN_ALL);        //使能P0数字信号输入功能
  133.     //<<AICUBE_USER_PORT0_INITIAL_BEGIN>>
  134.     // 在此添加用户初始化代码
  135.     //<<AICUBE_USER_PORT0_INITIAL_END>>
  136. }
  137. ////////////////////////////////////////
  138. // P6口初始化函数
  139. // 入口参数: 无
  140. // 函数返回: 无
  141. ////////////////////////////////////////
  142. void PORT6_Init(void)
  143. {
  144.     SetP6nInitLevelHigh(PIN_ALL);       //设置P6初始化电平
  145.     SetP6nQuasiMode(PIN_ALL);           //设置P6为准双向口模式
  146.     DisableP6nPullUp(PIN_ALL);          //关闭P6内部上拉电阻
  147.     DisableP6nSchmitt(PIN_ALL);         //使能P6施密特触发
  148.     SetP6nSlewRateNormal(PIN_ALL);      //设置P6一般翻转速度
  149.     SetP6nDrivingNormal(PIN_ALL);       //设置P6一般驱动能力
  150.     SetP6nDigitalInput(PIN_ALL);        //使能P6数字信号输入功能
  151.     //<<AICUBE_USER_PORT6_INITIAL_BEGIN>>
  152.     // 在此添加用户初始化代码
  153.     //<<AICUBE_USER_PORT6_INITIAL_END>>
  154. }
  155. ////////////////////////////////////////
  156. // P7口初始化函数
  157. // 入口参数: 无
  158. // 函数返回: 无
  159. ////////////////////////////////////////
  160. void PORT7_Init(void)
  161. {
  162.     SetP7nInitLevelHigh(PIN_ALL);       //设置P7初始化电平
  163.     SetP7nQuasiMode(PIN_ALL);           //设置P7为准双向口模式
  164.     DisableP7nPullUp(PIN_ALL);          //关闭P7内部上拉电阻
  165.     DisableP7nSchmitt(PIN_ALL);         //使能P7施密特触发
  166.     SetP7nSlewRateNormal(PIN_ALL);      //设置P7一般翻转速度
  167.     SetP7nDrivingNormal(PIN_ALL);       //设置P7一般驱动能力
  168.     SetP7nDigitalInput(PIN_ALL);        //使能P7数字信号输入功能
  169.     //<<AICUBE_USER_PORT7_INITIAL_BEGIN>>
  170.     // 在此添加用户初始化代码
  171.     //<<AICUBE_USER_PORT7_INITIAL_END>>
  172. }
  173. ////////////////////////////////////////
  174. // 定时器0初始化函数
  175. // 入口参数: 无
  176. // 函数返回: 无
  177. ////////////////////////////////////////
  178. void TIMER0_Init(void)
  179. {
  180. #define T0_PSCR                 (0)
  181. #define T0_RELOAD               (65536 - (float)SYSCLK / (T0_PSCR + 1) * 1000 / 1000000)
  182.     TIMER0_TimerMode();                 //设置定时器0为定时模式
  183.     TIMER0_1TMode();                    //设置定时器0为1T模式
  184.     TIMER0_Mode0();                     //设置定时器0为模式0 (16位自动重载模式)
  185.     TIMER0_DisableGateINT0();           //禁止定时器0门控
  186.     TIMER0_SetIntPriority(0);           //设置中断为最低优先级
  187.     TIMER0_EnableInt();                 //使能定时器0中断
  188.     TIMER0_SetPrescale(T0_PSCR);        //设置定时器0的8位预分频
  189.     TIMER0_SetReload16(T0_RELOAD);      //设置定时器0的16位重载值
  190.     TIMER0_Run();                       //定时器0开始运行
  191.     //<<AICUBE_USER_TIMER0_INITIAL_BEGIN>>
  192.     // 在此添加用户初始化代码
  193.     //<<AICUBE_USER_TIMER0_INITIAL_END>>
  194. }
  195. ////////////////////////////////////////
  196. // PWMA初始化函数
  197. // 入口参数: 无
  198. // 函数返回: 无
  199. ////////////////////////////////////////
  200. void PWMA_Init(void)
  201. {
  202.     PWMA_C1SwitchP6061();               //设置PWMA通道1数据端口: PWM1P (P6.1), PWM3N (P6.2)
  203.     PWMA_C2SwitchP6263();               //设置PWMA通道2数据端口: PWM2P (P6.3), PWM3N (P6.4)
  204.     PWMA_C3SwitchP6465();               //设置PWMA通道3数据端口: PWM3P (P6.4), PWM3N (P6.5)
  205.     PWMA_C4SwitchP6667();               //设置PWMA通道4数据端口: PWM4P (P6.6), PWM4N (P6.7)
  206.     HSPWMA_Disable();                   //关闭高速模式,使用同步方式进行初始化
  207.     PWMA_InternalClockMode();           //选择内部时钟模式
  208.     PWMA_SetClockDivider(0);            //设置16位预分频
  209.     PWMA_SetReload16(PWM_PERIOD);       //设置16位重载值
  210.     PWMA_BufferARR();                   //使能重载值寄存器预装载功能
  211.     PWMA_SetCounter(0);                 //初始化计数值
  212.     PWMA_CC1PDisable();                 //关闭通道
  213.     PWMA_CC1Output();                   //使能通道输出功能
  214.     PWMA_CC1PEnable();                  //打开通道
  215.     PWM_UpdateDuty(PWMA_CH1, 500);      //设置通道的PWM占空比
  216.     PWMA_OC1REFPWMMode1();              //设置通道输出参考信号为PWM模式1信号
  217.     PWMA_BufferCCR1();                  //使能CCRn预装载功能
  218.     PWMA_CC1PNonInverted();             //设置正极通道输出高电平有效
  219.     PWMA_EnablePWM1POutput();           //使能正极通道输出
  220.     PWMA_CC1NEnable();                  //打开负极通道
  221.     PWMA_CC1NNonInverted();             //设置负极通道输出高电平有效
  222.     PWMA_EnablePWM1NOutput();           //使能负极通道输出
  223.     PWMA_CC2PDisable();                 //关闭通道
  224.     PWMA_CC2Output();                   //使能通道输出功能
  225.     PWMA_CC2PEnable();                  //打开通道
  226.     PWM_UpdateDuty(PWMA_CH2, 500);      //设置通道的PWM占空比
  227.     PWMA_OC2REFPWMMode1();              //设置通道输出参考信号为PWM模式1信号
  228.     PWMA_BufferCCR2();                  //使能CCRn预装载功能
  229.     PWMA_CC2PNonInverted();             //设置正极通道输出高电平有效
  230.     PWMA_EnablePWM2POutput();           //使能正极通道输出
  231.     PWMA_CC2NEnable();                  //打开负极通道
  232.     PWMA_CC2NNonInverted();             //设置负极通道输出高电平有效
  233.     PWMA_EnablePWM2NOutput();           //使能负极通道输出
  234.     PWMA_CC3PDisable();                 //关闭通道
  235.     PWMA_CC3Output();                   //使能通道输出功能
  236.     PWMA_CC3PEnable();                  //打开通道
  237.     PWM_UpdateDuty(PWMA_CH3, 500);      //设置通道的PWM占空比
  238.     PWMA_OC3REFPWMMode1();              //设置通道输出参考信号为PWM模式1信号
  239.     PWMA_BufferCCR3();                  //使能CCRn预装载功能
  240.     PWMA_CC3PNonInverted();             //设置正极通道输出高电平有效
  241.     PWMA_EnablePWM3POutput();           //使能正极通道输出
  242.     PWMA_CC3NEnable();                  //打开负极通道
  243.     PWMA_CC3NNonInverted();             //设置负极通道输出高电平有效
  244.     PWMA_EnablePWM3NOutput();           //使能负极通道输出
  245.     PWMA_CC4PDisable();                 //关闭通道
  246.     PWMA_CC4Output();                   //使能通道输出功能
  247.     PWMA_CC4PEnable();                  //打开通道
  248.     PWM_UpdateDuty(PWMA_CH4, 500);      //设置通道的PWM占空比
  249.     PWMA_OC4REFPWMMode1();              //设置通道输出参考信号为PWM模式1信号
  250.     PWMA_BufferCCR4();                  //使能CCRn预装载功能
  251.     PWMA_CC4PNonInverted();             //设置正极通道输出高电平有效
  252.     PWMA_EnablePWM4POutput();           //使能正极通道输出
  253.     PWMA_CC4NEnable();                  //打开负极通道
  254.     PWMA_CC4NNonInverted();             //设置负极通道输出高电平有效
  255.     PWMA_EnablePWM4NOutput();           //使能负极通道输出
  256.     PWMA_EnableMainOutput();            //使能PWM主输出
  257.     PWMA_Run();                         //PWMA开始运行
  258.     //<<AICUBE_USER_PWM0_INITIAL_BEGIN>>
  259.     // 在此添加用户初始化代码
  260.     //<<AICUBE_USER_PWM0_INITIAL_END>>
  261. }
  262. ////////////////////////////////////////
  263. // 设置PWM通道输出占空比
  264. // 入口参数: PWMx: (目标PWM组和通道索引)
  265. //           nCompare: (PWM占空比值)
  266. //           iMode: (PWM输出模式:PWM_MODE1/PWM_MODE2)
  267. // 函数返回: 无
  268. ////////////////////////////////////////
  269. void PWM_UpdateDuty(uint8_t PWMx, uint16_t nCompare)
  270. {
  271.     switch (PWMx)
  272.     {
  273.     case PWMA_CH1:
  274.         PWMA_SetCCR1Value(nCompare);    //设置通道比较值
  275.         break;
  276.     case PWMA_CH2:
  277.         PWMA_SetCCR2Value(nCompare);    //设置通道比较值
  278.         break;
  279.     case PWMA_CH3:
  280.         PWMA_SetCCR3Value(nCompare);    //设置通道比较值
  281.         break;
  282.     case PWMA_CH4:
  283.         PWMA_SetCCR4Value(nCompare);    //设置通道比较值
  284.         break;
  285.     case PWMB_CH5:
  286.         PWMB_SetCCR5Value(nCompare);    //设置通道比较值
  287.         break;
  288.     case PWMB_CH6:
  289.         PWMB_SetCCR6Value(nCompare);    //设置通道比较值
  290.         break;
  291.     case PWMB_CH7:
  292.         PWMB_SetCCR7Value(nCompare);    //设置通道比较值
  293.         break;
  294.     case PWMB_CH8:
  295.         PWMB_SetCCR8Value(nCompare);    //设置通道比较值
  296.         break;
  297.     }
  298. }
  299. ////////////////////////////////////////
  300. // 读取PWM通道捕获值
  301. // 入口参数: PWMx: (目标PWM组和通道索引)
  302. // 函数返回: 捕获值
  303. ////////////////////////////////////////
  304. uint16_t PWM_ReadCapture(uint8_t PWMx)
  305. {
  306.     uint16_t cap;
  307.     switch (PWMx)
  308.     {
  309.     case PWMA_CH1:  cap = PWMA_ReadCCR1Value(); break;
  310.     case PWMA_CH2:  cap = PWMA_ReadCCR2Value(); break;
  311.     case PWMA_CH3:  cap = PWMA_ReadCCR3Value(); break;
  312.     case PWMA_CH4:  cap = PWMA_ReadCCR4Value(); break;
  313.     case PWMB_CH5:  cap = PWMB_ReadCCR5Value(); break;
  314.     case PWMB_CH6:  cap = PWMB_ReadCCR6Value(); break;
  315.     case PWMB_CH7:  cap = PWMB_ReadCCR7Value(); break;
  316.     case PWMB_CH8:  cap = PWMB_ReadCCR8Value(); break;
  317.     default: cap = 0;
  318.     }
  319.     return cap;
  320. }
  321. ////////////////////////////////////////
  322. // 设置高速模式PWM通道输出占空比
  323. // 入口参数: PWMx: (目标PWM组和通道索引)
  324. //           nCompare: (PWM占空比值)
  325. // 函数返回: 无
  326. ////////////////////////////////////////
  327. void HSPWM_UpdateDuty(uint8_t PWMx, uint16_t nCompare)
  328. {
  329.     switch (PWMx)
  330.     {
  331.     case PWMA_CH1:
  332.         HSPWMA_SetCCR1Value(nCompare);  //设置通道比较值
  333.         break;
  334.     case PWMA_CH2:
  335.         HSPWMA_SetCCR2Value(nCompare);  //设置通道比较值
  336.         break;
  337.     case PWMA_CH3:
  338.         HSPWMA_SetCCR3Value(nCompare);  //设置通道比较值
  339.         break;
  340.     case PWMA_CH4:
  341.         HSPWMA_SetCCR4Value(nCompare);  //设置通道比较值
  342.         break;
  343.     case PWMB_CH5:
  344.         HSPWMB_SetCCR5Value(nCompare);  //设置通道比较值
  345.         break;
  346.     case PWMB_CH6:
  347.         HSPWMB_SetCCR6Value(nCompare);  //设置通道比较值
  348.         break;
  349.     case PWMB_CH7:
  350.         HSPWMB_SetCCR7Value(nCompare);  //设置通道比较值
  351.         break;
  352.     case PWMB_CH8:
  353.         HSPWMB_SetCCR8Value(nCompare);  //设置通道比较值
  354.         break;
  355.     }
  356. }
  357. ////////////////////////////////////////
  358. // 读取高速模式PWM通道捕获值
  359. // 入口参数: PWMx: (目标PWM组和通道索引)
  360. // 函数返回: 捕获值
  361. ////////////////////////////////////////
  362. uint16_t HSPWM_ReadCapture(uint8_t PWMx)
  363. {
  364.     uint16_t cap;
  365.     switch (PWMx)
  366.     {
  367.     case PWMA_CH1:  cap = HSPWMA_ReadCCR1Value();   break;
  368.     case PWMA_CH2:  cap = HSPWMA_ReadCCR2Value();   break;
  369.     case PWMA_CH3:  cap = HSPWMA_ReadCCR3Value();   break;
  370.     case PWMA_CH4:  cap = HSPWMA_ReadCCR4Value();   break;
  371.     case PWMB_CH5:  cap = HSPWMB_ReadCCR5Value();   break;
  372.     case PWMB_CH6:  cap = HSPWMB_ReadCCR6Value();   break;
  373.     case PWMB_CH7:  cap = HSPWMB_ReadCCR7Value();   break;
  374.     case PWMB_CH8:  cap = HSPWMB_ReadCCR8Value();   break;
  375.     default: cap = 0;
  376.     }
  377.     return cap;
  378. }
  379. ////////////////////////////////////////
  380. // 异步方式读取PWMA特殊功能寄存器
  381. // 入口参数: addr: (PWMA特殊功能寄存器的低7位)
  382. // 函数返回: 寄存器的值
  383. ////////////////////////////////////////;
  384. uint8_t HSPWMA_ReadReg(uint8_t addr)
  385. {
  386.     uint8_t dat;
  387.     while (HSPWMA_CheckBusy());         //等待前一个异步读写完成
  388.     HSPWMA_AsyncRead(addr, dat);        //触发异步方式读取寄存器
  389.     return dat;
  390. }
  391. ////////////////////////////////////////
  392. // 异步方式写PWMA特殊功能寄存器
  393. // 入口参数: addr: (PWMA特殊功能寄存器的低7位)
  394. //           dat: (待写入的数据)
  395. // 函数返回: 无
  396. ////////////////////////////////////////;
  397. void HSPWMA_WriteReg(uint8_t addr, uint8_t dat)
  398. {
  399.     while (HSPWMA_CheckBusy());         //等待前一个异步读写完成
  400.     HSPWMA_AsyncWrite(addr, dat);       //触发异步方式写寄存器
  401. }
  402. ////////////////////////////////////////
  403. // 异步方式读取PWMB特殊功能寄存器
  404. // 入口参数: addr: (PWMB特殊功能寄存器的低7位)
  405. // 函数返回: 寄存器的值
  406. ////////////////////////////////////////;
  407. uint8_t HSPWMB_ReadReg(uint8_t addr)
  408. {
  409.     uint8_t dat;
  410.     while (HSPWMB_CheckBusy());         //等待前一个异步读写完成
  411.     HSPWMB_AsyncRead(addr, dat);        //触发异步方式读取寄存器
  412.     return dat;
  413. }
  414. ////////////////////////////////////////
  415. // 异步方式写PWMB特殊功能寄存器
  416. // 入口参数: addr: (PWMB特殊功能寄存器的低7位)
  417. //           dat: (待写入的数据)
  418. // 函数返回: 无
  419. ////////////////////////////////////////;
  420. void HSPWMB_WriteReg(uint8_t addr, uint8_t dat)
  421. {
  422.     while (HSPWMB_CheckBusy());         //等待前一个异步读写完成
  423.     HSPWMB_AsyncWrite(addr, dat);       //触发异步方式写寄存器
  424. }
  425. ////////////////////////////////////////
  426. // USB库初始化函数
  427. // 入口参数: 无
  428. // 函数返回: 无
  429. ////////////////////////////////////////
  430. void USBLIB_Init(void)
  431. {
  432.     usb_init();                         //初始化USB模块
  433.     USB_SetIntPriority(0);              //设置中断为最低优先级
  434.     set_usb_ispcmd("@STCISP#");         //设置USB不停电下载命令
  435.     //<<AICUBE_USER_USBLIB_INITIAL_BEGIN>>
  436.     // 在此添加用户初始化代码
  437.     //<<AICUBE_USER_USBLIB_INITIAL_END>>
  438. }
  439. ////////////////////////////////////////
  440. // 等待USB配置完成函数
  441. // 入口参数: 无
  442. // 函数返回: 无
  443. ////////////////////////////////////////
  444. void USBLIB_WaitConfiged(void)
  445. {
  446.     while (DeviceState != DEVSTATE_CONFIGURED) //等待USB完成配置
  447.         WDT_Clear();                    //清看门狗定时器 (防止硬件自动使能看门狗)
  448. }
  449. ////////////////////////////////////////
  450. // USB设备接收数据处理程序
  451. // 入口参数: 无
  452. // 函数返回: 无
  453. // bUsbOutReady:USB设备接收数据标志位
  454. // OutNumber:USB设备接收到的数据长度
  455. // UsbOutBuffer:保存USB设备接收到的数据
  456. ////////////////////////////////////////
  457. void USBLIB_OUT_Done(void)
  458. {
  459.     if (bUsbOutReady)                   //查询是否有接收到USB主机发送数据
  460.     {
  461.         //<<AICUBE_USER_USBLIB_ISR_CODE1_BEGIN>>
  462.         // 在此添加中断函数用户代码
  463.         USB_SendData(UsbOutBuffer, OutNumber); // 原路返回, 用于测试
  464.         // 在此处添加用户处理接收数据的代码
  465.         //<<AICUBE_USER_USBLIB_ISR_CODE1_END>>
  466.         usb_OUT_done();                 //当前包的数据处理完成,通知USB主机可以发送下一包数据
  467.     }
  468. }
  469. ////////////////////////////////////////
  470. // 定时器0中断服务程序
  471. // 入口参数: 无
  472. // 函数返回: 无
  473. ////////////////////////////////////////
  474. void TIMER0_ISR(void) interrupt TMR0_VECTOR
  475. {
  476.     //<<AICUBE_USER_TIMER0_ISR_CODE1_BEGIN>>
  477.     // 在此添加中断函数用户代码
  478.     if (!PWM1_Flag)
  479.     {
  480.         PWM1_Duty++;
  481.         if (PWM1_Duty > PWM_PERIOD)
  482.             PWM1_Flag = 1;
  483.     }
  484.     else
  485.     {
  486.         PWM1_Duty--;
  487.         if (PWM1_Duty <= 0)
  488.             PWM1_Flag = 0;
  489.     }
  490.     if (!PWM2_Flag)
  491.     {
  492.         PWM2_Duty++;
  493.         if (PWM2_Duty > PWM_PERIOD)
  494.             PWM2_Flag = 1;
  495.     }
  496.     else
  497.     {
  498.         PWM2_Duty--;
  499.         if (PWM2_Duty <= 0)
  500.             PWM2_Flag = 0;
  501.     }
  502.     if (!PWM3_Flag)
  503.     {
  504.         PWM3_Duty++;
  505.         if (PWM3_Duty > PWM_PERIOD)
  506.             PWM3_Flag = 1;
  507.     }
  508.     else
  509.     {
  510.         PWM3_Duty--;
  511.         if (PWM3_Duty <= 0)
  512.             PWM3_Flag = 0;
  513.     }
  514.     if (!PWM4_Flag)
  515.     {
  516.         PWM4_Duty++;
  517.         if (PWM4_Duty > PWM_PERIOD)
  518.             PWM4_Flag = 1;
  519.     }
  520.     else
  521.     {
  522.         PWM4_Duty--;
  523.         if (PWM4_Duty <= 0)
  524.             PWM4_Flag = 0;
  525.     }
  526.     UpdatePwm();
  527.     //<<AICUBE_USER_TIMER0_ISR_CODE1_END>>
  528. }
  529. //<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
  530. // 在此添加用户函数实现代码
  531. //========================================================================
  532. // 函数: UpdatePwm(void)
  533. // 描述: 更新PWM占空比.
  534. // 参数: none.
  535. // 返回: none.
  536. // 版本: V1.0, 2012-11-22
  537. //========================================================================
  538. void UpdatePwm(void)
  539. {
  540.     PWM_UpdateDuty(PWMA_CH1, PWM1_Duty);
  541.     PWM_UpdateDuty(PWMA_CH2, PWM2_Duty);
  542.     PWM_UpdateDuty(PWMA_CH3, PWM3_Duty);
  543.     PWM_UpdateDuty(PWMA_CH4, PWM4_Duty);
  544. }
  545. //<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:201
  • 最近打卡:2026-02-12 09:27:55

1

主题

45

回帖

852

积分

高级会员

积分
852
发表于 2025-11-25 16:40:14 | 显示全部楼层
最后一课

CDC串口控制PWM(使用led灯模拟电机)

  1. tmp_16 = atoi(UsbOutBuffer);
  2.         printf_usb("tmp_16: %d\r\n", tmp_16);
  3.         if (tmp_16 < 0)
  4.         {
  5.             // 反转
  6.             PWM4_Duty = -tmp_16;
  7.         }
  8.         else
  9.         {
  10.             // 正转
  11.             PWM4_Duty = tmp_16;
  12.         }
  13.         if (PWM4_Duty > PWM_RELOAD + 1)
  14.         {
  15.             PWM4_Duty = PWM_RELOAD + 1;
  16.         }
  17.         printf_usb("PWM4_Duty: %d\r\n", PWM4_Duty);
  18.         if (PWM4_Duty == 0)
  19.         {
  20.             // 停止
  21.             PWMA_DisablePWM4NOutput();
  22.             PWMA_DisablePWM4POutput();
  23.             P66 = 1;
  24.             P67 = 1;
  25.         }
  26.         else if (tmp_16 > 0)
  27.         {
  28.             // 正转
  29.             PWMA_EnablePWM4POutput();
  30.             PWMA_DisablePWM4NOutput();
  31.             PWMA_CC4PInverted(); // 开发板上led低电平导通
  32.             P67 = 1;
  33.         }
  34.         else if (tmp_16 < 0)
  35.         {
  36.             // 反转
  37.             PWMA_DisablePWM4POutput();
  38.             PWMA_EnablePWM4NOutput();
  39.             PWMA_CC4NInverted(); // 开发板上led低电平导通
  40.             P66 = 1;
  41.         }
  42.         memset(UsbOutBuffer, 0, OutNumber);
复制代码

回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-2-12 18:02 , Processed in 0.126609 second(s), 73 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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