数码之家

 找回密码
 立即注册
搜索
查看: 2424|回复: 3

征集 开源 FOC 电机控制方案@STC32F12K54-64MHz 为高校《单片机应用及原理》课程

[复制链接]
发表于 2023-6-13 10:04:47 | 显示全部楼层 |阅读模式
本帖最后由 钟山风雨起苍黄 于 2023-6-13 10:10 编辑

征集 开源 FOC 电机控制方案@STC32F12K54-64MHz 为高校《单片机应用及原理》课程
===硬件材料费 www.STCAIMCU.com 公司出,  辛苦费 RMB5000 !
有强大的专门支持FOC运算硬件单精度浮点运算器,外部加上普通的运放就可以做FOC控制
32位8051世界共同进步,期待大家在此开源 STC32F12K54-64MHz-LQFP48的 FOC 方案

32位8051世界大礼,追风剑-STC32F12K54-64MHz,还是 STC的 那个 8051 回来了 !
少年强则国强,6/1 儿童节 新生代32位8051全面出击,全球 【免费+包邮】 送
硬件单精度浮点运算器/8051世界革命性的进步,64MHz 主频  ! 强大的DMA支持
===8K 高速 edata/堆栈/RTOS, 4k xdata/DMA缓冲区, 288MHz PWM时钟源
===奋起一剑斩不周,扳倒乾坤天且休!
自带硬件 USB 仿真】,【硬件 USB 高速下载】,同时支持【SWD仿真】,【串口仿真】

追风剑-STC32F12K54-64MHz-LQFP48转DIP48核心功能实验板


这个 STC32F12K54 的内部高达 [60MHz-HIRC] 的高速 HIRC,  不好做,
【5.5V ~ 2V 的压飘】,【-40度 ~ +85度的温漂】,对 60MHz的内部 HIRC是一大难题 !
暂时的解决方案就是用外部 32768 RTC 时钟来自动动态追频,动态调教内部高频时钟到 60MHz,
误差在 +/- 0.3%
用内部高速IRC取代外部高频时钟的好处是 【对外电磁辐射小抗干扰强

后记,网友调侃:
平常吹水,自说水平高,现在【没能力开源个8051做的 FOC 方案,帮助大家共同进步 】!
只能说还是要虚心学习,共同进步


深圳国芯人工智能有限公司-核心功能实验板 (stcai.com)

深圳国芯人工智能有限公司 (stcai.com)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
发表于 2023-6-13 11:41:58 | 显示全部楼层
围观学习,开眼界。
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2023-6-14 08:45:24 | 显示全部楼层
250MHz时钟源 PWM,  STC32F12K54-64MHz
——高速PWM应用1:  高速PWM输出
——高速PWM应用2:捕获外部高速脉宽(查询方式)
——高速PWM应用3:捕获外部高速脉宽(中断方式)


高速PWM应用2: 捕获外部高速脉宽(查询方式)
高速PWM可使用内建500MHz高速HPLL作为时钟源【输出高速PWM】/【捕获外部高速脉宽】
(注:500MHz的HPLL时钟2分频输出50%占空比的PLL输出时钟可作为高速PWM的时钟源)

  • /*************  功能说明    **************
  • 时钟说明:由内部IRC产生24MHz的时钟分频为6M提供给HPLL当作HPLL输入时钟,PLL锁频到246MHz输出作为高速PWM的时钟源,
  • PWM高速输出说明:PWMA的CC1通道配置为输出模式,并从P2.0口输出频率为24.6MHz,占空比为20%的PWM型号
  • PWM高速捕获说明:PWMB的CC5和CC6通道配置为捕获输入模式,CC5口P2.0口捕获信号的周期值,CC6从P2.0口捕获信号的占空比
  • 测试说明:最后通过查询方式得到周期值和占空比并从串口送到PC显示
  • 下载时, 选择默认IRC时钟 24MHz。
  • ******************************************/
  • #include "stc32g.h"
  • #include "stdio.h"
  • #define FOSC            24000000UL
  • #define BAUD            (65536 - FOSC/4/115200)
  • #define HSCK_MCLK       0
  • #define HSCK_PLL        1
  • #define HSCK_SEL        HSCK_PLL
  • #define HSIOCK          0x40
  • #define ENHPLL          0x80
  • #define HPLLDIV_52      0x00
  • #define HPLLDIV_54      0x01
  • #define HPLLDIV_56      0x02
  • #define HPLLDIV_58      0x03
  • #define HPLLDIV_60      0x04
  • #define HPLLDIV_62      0x05
  • #define HPLLDIV_64      0x06
  • #define HPLLDIV_66      0x07
  • #define HPLLDIV_68      0x08
  • #define HPLLDIV_70      0x09
  • #define HPLLDIV_72      0x0A
  • #define HPLLDIV_74      0x0B
  • #define HPLLDIV_76      0x0C
  • #define HPLLDIV_78      0x0D
  • #define HPLLDIV_80      0x0E
  • #define HPLLDIV_82      0x0F
  • #define ENCKM           0x80
  • #define PCKI_MSK        0x60
  • #define PCKI_D1         0x00
  • #define PCKI_D2         0x20
  • #define PCKI_D4         0x40
  • #define PCKI_D8         0x60
  • void delay()
  • {
  •     int i;
  •     for (i=0; i<100; i++);
  • }
  • char ReadPWMA(char addr)
  • {
  •     char dat;
  •     while (HSPWMA_ADR & 0x80);              //等待前一个异步读写完成
  •     HSPWMA_ADR = addr | 0x80;               //设置间接访问地址,只需要设置原XFR地址的低7位
  •                                             //HSPWMA_ADDR寄存器的最高位写1,表示读数据
  •     while (HSPWMA_ADR & 0x80);              //等待当前异步读取完成
  •     dat = HSPWMA_DAT;                       //读取异步数据
  •     return dat;
  • }
  • void WritePWMA(char addr, char dat)
  • {
  •     while (HSPWMA_ADR & 0x80);              //等待前一个异步读写完成
  •     HSPWMA_DAT = dat;                       //准备需要写入的数据
  •     HSPWMA_ADR = addr & 0x7f;               //设置间接访问地址,只需要设置原XFR地址的低7位
  •                                             //HSPWMA_ADDR寄存器的最高位写0,表示写数据
  • }
  • char ReadPWMB(char addr)
  • {
  •     char dat;
  •     while (HSPWMB_ADR & 0x80);              //等待前一个异步读写完成
  •     HSPWMB_ADR = addr | 0x80;               //设置间接访问地址,只需要设置原XFR地址的低7位
  •                                             //HSPWMB_ADDR寄存器的最高位写1,表示读数据
  •     while (HSPWMB_ADR & 0x80);              //等待当前异步读取完成
  •     dat = HSPWMB_DAT;                       //读取异步数据
  •     return dat;
  • }
  • void WritePWMB(char addr, char dat)
  • {
  •     while (HSPWMB_ADR & 0x80);              //等待前一个异步读写完成
  •     HSPWMB_DAT = dat;                       //准备需要写入的数据
  •     HSPWMB_ADR = addr & 0x7f;               //设置间接访问地址,只需要设置原XFR地址的低7位
  •                                             //HSPWMB_ADDR寄存器的最高位写0,表示写数据
  • }
  • int main()
  • {
  •     EAXFR = 1;
  •     P0M0 = 0; P0M1 = 0;
  •     P1M0 = 0; P1M1 = 0;
  •     P2M0 = 0; P2M1 = 0;
  •     P3M0 = 0; P3M1 = 0;
  •     P4M0 = 0; P4M1 = 0;
  •     P5M0 = 0; P5M1 = 0;
  •     SCON = 0x52;
  •     AUXR = 0x40;
  •     TMOD = 0x00;
  •     TL1 = BAUD;
  •     TH1 = BAUD >> 8;
  •     TR1 = 1;
  •     //选择HPLL输入时钟分频,保证输入时钟为6M
  •     USBCLK &= ~PCKI_MSK;
  • #if (FOSC == 6000000UL)
  •     USBCLK |= PCKI_D1;                      //PLL输入时钟1分频
  • #elif (FOSC == 12000000UL)
  •     USBCLK |= PCKI_D2;                      //PLL输入时钟2分频
  • #elif (FOSC == 24000000UL)
  •     USBCLK |= PCKI_D4;                      //PLL输入时钟4分频
  • #elif (FOSC == 48000000UL)
  •     USBCLK |= PCKI_D8;                      //PLL输入时钟8分频
  • #else
  •     USBCLK |= PCKI_D4;                      //默认PLL输入时钟4分频
  • #endif
  •     //设置HPLL的除频系数
  • //    HPLLCR = HPLLDIV_52;                  //F_HPLL=6M*52/2=156M
  • //    HPLLCR = HPLLDIV_54;                  //F_HPLL=6M*54/2=162M
  • //    HPLLCR = HPLLDIV_56;                  //F_HPLL=6M*56/2=168M
  • //    HPLLCR = HPLLDIV_58;                  //F_HPLL=6M*58/2=174M
  • //    HPLLCR = HPLLDIV_60;                  //F_HPLL=6M*60/2=180M
  • //    HPLLCR = HPLLDIV_62;                  //F_HPLL=6M*62/2=186M
  • //    HPLLCR = HPLLDIV_64;                  //F_HPLL=6M*64/2=192M
  • //    HPLLCR = HPLLDIV_66;                  //F_HPLL=6M*66/2=198M
  • //    HPLLCR = HPLLDIV_68;                  //F_HPLL=6M*68/2=204M
  • //    HPLLCR = HPLLDIV_70;                  //F_HPLL=6M*70/2=210M
  • //    HPLLCR = HPLLDIV_72;                  //F_HPLL=6M*72/2=216M
  • //    HPLLCR = HPLLDIV_74;                  //F_HPLL=6M*74/2=222M
  • //    HPLLCR = HPLLDIV_76;                  //F_HPLL=6M*76/2=228M
  • //    HPLLCR = HPLLDIV_78;                  //F_HPLL=6M*78/2=234M
  • //    HPLLCR = HPLLDIV_80;                  //F_HPLL=6M*80/2=240M
  •     HPLLCR = HPLLDIV_82;                    //F_HPLL=6M*82/2=246M
  •     //启动HPLL
  •     HPLLCR |= ENHPLL;                       //使能HPLL
  •     delay();                                //等待HPLL时钟稳定
  •     //选择HSPWM/HSSPI时钟
  • #if (HSCK_SEL == HSCK_MCLK)
  •     CLKSEL &= ~HSIOCK;                      //HSPWM/HSSPI选择主时钟为时钟源
  • #elif (HSCK_SEL == HSCK_PLL)
  •     CLKSEL |= HSIOCK;                       //HSPWM/HSSPI选择PLL输出时钟为时钟源
  • #else
  •     CLKSEL &= ~HSIOCK;                      //默认HSPWM/HSSPI选择主时钟为时钟源
  • #endif
  •     HSCLKDIV = 0;                           //HSPWM/HSSPI时钟源不分频
  •     HSPWMA_CFG = 0x03;                      //使能PWMA相关寄存器异步访问功能
  •     HSPWMA_CFG = 0x03;                      //使能PWMA相关寄存器异步访问功能
  •     HSPWMB_CFG = 0x03;                      //使能PWMB相关寄存器异步访问功能
  •     PWMA_PS = 0x01;                         //PWMA_CC1高速PWM输出到P2.0口
  •                                             //PWMB_CC5/PWMB_CC6从P2.0口进行捕获
  •                                             //注意:PWMA_PS和PWMB_PS属于I/O控制寄存器,不能使用异步方式进行读写
  •     //通过异步方式设置PWMA/PWMB的相关寄存器
  •     WritePWMA((char)&PWMA_CCER1, 0x00);
  •     WritePWMA((char)&PWMA_CCMR1, 0x00);     //CC1为输出模式
  •     WritePWMA((char)&PWMA_CCMR1, 0x60);     //OC1REF输出PWM1(CNT<CCR时输出有效电平1)
  •     WritePWMA((char)&PWMA_CCER1, 0x05);     //使能CC1/CC1N上的输出功能
  •     WritePWMA((char)&PWMA_ENO, 0x01);       //使能PWM信号输出到端口
  •     WritePWMA((char)&PWMA_BKR, 0x80);       //使能主输出
  •     WritePWMA((char)&PWMA_CCR1H, 0x00);     //设置输出PWM的占空比
  •     WritePWMA((char)&PWMA_CCR1L, 0x02);
  •     WritePWMA((char)&PWMA_ARRH, 0x00);      //设置输出PWM的周期
  •     WritePWMA((char)&PWMA_ARRL, 0x09);
  •     WritePWMA((char)&PWMA_CR1, 0x01);       //开始PWM计数
  •     WritePWMB((char)&PWMB_CCER1, 0x00);
  •     WritePWMB((char)&PWMB_CCMR1, 0x01);     //CC5为输入模式,且映射到TI5FP5上
  •     WritePWMB((char)&PWMB_CCMR2, 0x02);     //CC6为输入模式,且映射到TI6FP5上
  •     WritePWMB((char)&PWMB_CCER1, 0x31);     //使能CC5上的捕获功能(上升沿捕获)
  •     WritePWMB((char)&PWMB_SMCR, 0x54);      //上升沿复位模式
  •     WritePWMB((char)&PWMB_CR1, 0x01);       //开始PWM计数
  •     while (1)
  •     {
  •         if (ReadPWMB((char)&PWMB_SR1) & 0x02)   //等待捕获完成
  •         {
  •             WritePWMB((char)&PWMB_SR1, 0x00);   //清除完成标志
  •             //读取捕获到的周期值
  •             printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR5H) & 0xff);
  •             printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR5L) & 0xff);
  •             printf(" ");
  •             //读取捕获到的占空比值
  •             printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR6H) & 0xff);
  •             printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR6L) & 0xff);
  •             printf("\n");
  •         }
  •     }
  • }





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2023-6-14 13:44:51 | 显示全部楼层
307MHz时钟源 PWM, STC32F12K54-64MHz
——高速PWM应用1:  高速PWM输出
——高速PWM应用2:捕获外部高速脉宽(查询方式)
——高速PWM应用3:捕获外部高速脉宽(中断方式)

高速PWM应用1: 高速PWM输出(CPU工作频率60MHz+ICache)
高速PWM可使用内建500MHz高速HPLL作为时钟源【输出高速PWM】/【捕获外部高速脉宽】
(特别的:高速HPLL时钟输入范围6M~12M。本范例高速HPLL输入频率为7.5MHz,
产生615MHz的HPLL时钟2分频输出50%占空比的PLL输出频率307.5MHz可作为高速PWM的时钟源)
  • /*************  功能说明    **************
  • 时钟说明:由内部IRC产生60MHz的时钟当作CPU时钟,同时8分频产生7.5M提供给HPLL
  •           当作HPLL输入时钟,PLL锁频到307.5MHz输出作为高速PWM的时钟源,
  • PWM高速输出说明:PWMA的CC1通道配置为输出模式,并从P1.0/P1.1口输出频率为3.705MHz,
  •                  占空比为50%的互补对称带死区的PWM波形
  • CPU时钟说明:ISP下载软件根据CPU工作频率为60MHz,会自动将WTST设置为2
  •              用户代码中不用对WTST进行设置。范例中使能了ICACHE功能,
  •              可有效的提高代码执行效率
  • 下载时, 选择默认IRC时钟 60MHz。
  • ******************************************/
  • #include "stc32g.h"
  • #define FOSC            60000000UL
  • #define HSCK_MCLK       0
  • #define HSCK_PLL        1
  • #define HSCK_SEL        HSCK_PLL
  • #define HSIOCK          0x40
  • #define ENHPLL          0x80
  • #define HPLLDIV_52      0x00
  • #define HPLLDIV_54      0x01
  • #define HPLLDIV_56      0x02
  • #define HPLLDIV_58      0x03
  • #define HPLLDIV_60      0x04
  • #define HPLLDIV_62      0x05
  • #define HPLLDIV_64      0x06
  • #define HPLLDIV_66      0x07
  • #define HPLLDIV_68      0x08
  • #define HPLLDIV_70      0x09
  • #define HPLLDIV_72      0x0A
  • #define HPLLDIV_74      0x0B
  • #define HPLLDIV_76      0x0C
  • #define HPLLDIV_78      0x0D
  • #define HPLLDIV_80      0x0E
  • #define HPLLDIV_82      0x0F
  • #define ENCKM           0x80
  • #define PCKI_MSK        0x60
  • #define PCKI_D1         0x00
  • #define PCKI_D2         0x20
  • #define PCKI_D4         0x40
  • #define PCKI_D8         0x60
  • void delay()
  • {
  •     int i;
  •     for (i=0; i<100; i++);
  • }
  • void ICacheOn()
  • {
  •     bit fEA;
  •     if (WTST > 0)                           //WTST为0时不需要且不能使能ICACHE
  •     {
  •         fEA = EA;                           //保存EA
  •         EA = 0;                             //关闭中断
  •         _nop_();
  •         _nop_();
  •         TA = 0xaa;                          //写入触发命令序列1
  •                                             //此处不能有其他任何指令
  •         TA = 0x55;                          //写入触发命令序列2
  •                                             //此处不能有其他任何指令
  •         ICHECR = 0x01;                      //写保护暂时关闭,可以修改ICHECR中的EN位
  •                                             //EN位再次进入写保护状态
  •         _nop_();
  •         _nop_();
  •         EA = fEA;                           //恢复EA
  •     }
  • }
  • char ReadPWMA(char addr)
  • {
  •     char dat;
  •     while (HSPWMA_ADR & 0x80);              //等待前一个异步读写完成
  •     HSPWMA_ADR = addr | 0x80;               //设置间接访问地址,只需要设置原XFR地址的低7位
  •                                             //HSPWMA_ADDR寄存器的最高位写1,表示读数据
  •     while (HSPWMA_ADR & 0x80);              //等待当前异步读取完成
  •     dat = HSPWMA_DAT;                       //读取异步数据
  •     return dat;
  • }
  • void WritePWMA(char addr, char dat)
  • {
  •     while (HSPWMA_ADR & 0x80);              //等待前一个异步读写完成
  •     HSPWMA_DAT = dat;                       //准备需要写入的数据
  •     HSPWMA_ADR = addr & 0x7f;               //设置间接访问地址,只需要设置原XFR地址的低7位
  •                                             //HSPWMA_ADDR寄存器的最高位写0,表示写数据
  • }
  • int main()
  • {
  •     ICacheOn();                             //使能ICACHE功能
  •     EAXFR = 1;
  •     P0M0 = 0; P0M1 = 0;
  •     P1M0 = 0; P1M1 = 0;
  •     P2M0 = 0; P2M1 = 0;
  •     P3M0 = 0; P3M1 = 0;
  •     P4M0 = 0; P4M1 = 0;
  •     P5M0 = 0; P5M1 = 0;
  •     //选择HPLL输入时钟分频
  •     USBCLK &= ~PCKI_MSK;
  •     USBCLK |= PCKI_D8;                      //PLL输入时钟8分频
  •     //设置HPLL的除频系数
  •     HPLLCR = HPLLDIV_82;                    //F_HPLL=60M/8*82/2=307.5M
  •     //启动HPLL
  •     HPLLCR |= ENHPLL;                       //使能HPLL
  •     delay();                                //等待HPLL时钟稳定
  •     //选择HSPWM/HSSPI时钟
  • #if (HSCK_SEL == HSCK_MCLK)
  •     CLKSEL &= ~HSIOCK;                      //HSPWM/HSSPI选择主时钟为时钟源
  • #elif (HSCK_SEL == HSCK_PLL)
  •     CLKSEL |= HSIOCK;                       //HSPWM/HSSPI选择PLL输出时钟为时钟源
  • #else
  •     CLKSEL &= ~HSIOCK;                      //默认HSPWM/HSSPI选择主时钟为时钟源
  • #endif
  •     HSCLKDIV = 0;                           //HSPWM/HSSPI时钟源不分频
  •     HSPWMA_CFG = 0x03;                      //使能PWMA相关寄存器异步访问功能
  •     PWMA_PS = 0x00;                         //PWMA_CC1/CC1N高速PWM输出到CC1/CC1N口
  •                                             //注意:PWMA_PS属于I/O控制寄存器,不能使用异步方式进行读写
  •     //通过异步方式设置PWMA的相关寄存器
  •     WritePWMA((char)&PWMA_CCER1, 0x00);
  •     WritePWMA((char)&PWMA_CCMR1, 0x00);     //CC1为输出模式
  •     WritePWMA((char)&PWMA_CCMR1, 0x60);     //OC1REF输出PWM1(CNT<CCR时输出有效电平1)
  •     WritePWMA((char)&PWMA_CCER1, 0x05);     //使能CC1/CC1N上的输出功能
  •     WritePWMA((char)&PWMA_ENO, 0x03);       //使能PWM信号输出到端口P1.0/P1.1
  •     WritePWMA((char)&PWMA_BKR, 0x80);       //使能主输出
  •     WritePWMA((char)&PWMA_CCR1H, 0);        //设置PWM占空比为50个PWM时钟
  •     WritePWMA((char)&PWMA_CCR1L, 50);
  •     WritePWMA((char)&PWMA_ARRH, 0);         //设置输出PWM的周期为100个PWM时钟
  •     WritePWMA((char)&PWMA_ARRL, 99);
  •     WritePWMA((char)&PWMA_DTR, 10);         //设置互补对称输出PWM的死区
  •     WritePWMA((char)&PWMA_CR1, 0x01);       //开始PWM计数
  • //  P2 = ReadPWMA((char)&PWMA_ARRH);        //异步方式读取寄存器
  • //  P0 = ReadPWMA((char)&PWMA_ARRL);
  •     while (1);
  • }


[color=rgb(51, 102, 153) !important]复制代码

[color=rgb(51, 102, 153) !important]


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

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

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-3 11:10 , Processed in 0.187200 second(s), 12 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

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