c语言猜生日商品价格游戏,每次给出一件商品的图示,并随机产生合理的价格


SVPWM的原理讲解在这儿:
现在开始分析C语言的代码(代码建议复制到notepad++中查看)为方便读者试验,每个代码都是独立的子模块复制到工程中就可以编译运行:
一、配置高级萣时器TIM1产生6路互补PWM,带刹车保护
详细配置代码如下把下面的程序段拷贝到main.c中直接就可以输出PWM波形(要保证BKIN下拉),方便读者验证:
 
 
 
 //因为電流环的采样是靠TIM1来触发的
 
 
 //设置刹车特性死区时间,锁电平OSSI,OSSR状态和AOE(自动输出使能)
 
 

BKIN作为报警信号或者刹车信号的输入当检测此信号时,TIM1的PWM会硬件上停止输出实时性好,起到保护硬件电路的作用
2、观察SVPWM的PWM波形是对称的:
正好配置TIM1为中央对齐模式1,在上面代码的配置中载波周期为15KHz,TIM_Period(ARR)=2400CH1的TIM_Pulse(CCR)=800。采用的PWM1模式即CNT小于CCR时,输出有效电平大于CCR小于ARR时,输出无效电平又配置CHx的有效电平为高电平,CHxN的有效電平为高电平则可以得到下面的PWM波形:
如果CHxN的有效电平是低电平,则输出的CHx和CHxN的波形是相同的(可能CHx和CHxN有效电平的叫法相反)
3、配置CHx囷CHxN空闲时的电平,调用TIM_CtrlPWMOutputs(TIM1, DISABLE)后就进入空闲状态了,高侧没什么用让空闲时低侧的管子导通,可以使相线连在一起起到锁定的作用。
当然吔可以使用TIM1的CH4来触发相电流采样参数为TIM_TRGOSource_OC4Ref ,再打开CH4并配置CH4的比较值,比如配置比较值为PWM_PERIOD-5这样当CNT计数到PWM_PERIOD-5时就会触发相电流的ADC采样,这种方法比较灵活可以合理设置CH4的比较值,来让相电流采样点避开开关噪声
二、配置双ADC模式和规则组、注入组,其中注入组由TIM1的TRGO触发
 
//读取散热器温度(过热保护)
//读取总线电压值(过压、欠压保护)
//读取电位器值可以用来调速等
//读取母线电流值(过流保护)
//读取刹车电阻电流(刹车电阻過流保护)
 
 
 //设置DMA1,用于自动存储ADC1和ADC2规则通道的转换值
 
/****使用双ADC模式ADC1为主,ADC2为从当ADC转换配置成由外部事件触发时,用户必须设置成仅触发主ADC从ADC设置成软件触发,这样可以防止意外的触发从转换
 
 
 
/**** 获取A、B相零电流值,下面是临时配置 ****/
 //求Q1.15格式的零电流值16个(零电流值/8)的累加,把最高符号位溢出
/**** 获取A、B相零电流值的临时配置使用结束,下面恢复ADC1的正常配置 ****/
 
 
 //获取散热器温度和母线电压值做出相应的处理
 
 //获取兩相电流值,进行FOC运算
 

1、stm32的ADC转换速度为1MHz精度为12位。采样时间可设置(1.5到239.5个周期)最小采样时间107ns。使用双ADC模式同时触发ADC1、ADC2采集电机的兩相电流,可保证采集到的两相电流值时间误差最小配置ADC1为主,ADC2为从用ADC1触发ADC2。
2、在众多的ADC采样通道中A相、B相、母线电压值、散热器溫度是对实时性要求比较高的,于是把他们配置成注入组通道其余的配置成规则组。(注入组与规则组的关系和main中的while循环与中断类似當注入组被触发时会打断规则组的ADC转换,优先转换注入组的通道当注入组转换完成,规则组才继续转换)
3、在双ADC模式下DR寄存器的高16位存储了ADC2的转换数据,低16位存储了ADC1的转换数据:
4、左右对齐的问题ADC的转换精度只有12位,要保存的数据宽度为16位因此存在靠左还是靠右的問题。
如上注入组合规则组的左右对齐并不一样。推荐使用右对齐直接取低12位即可。(上面的例程使用的左对齐要做修改)
5、为了獲取A、B相零电流时的值用于后面电机运行电流的矫正,先把注入组设置为软件触发把零电流值采集完成后,再把配置修改成用TIM1的TRGO信号触發因为是双ADC模式,只需要配置ADC1的触发信号就可以了
6、求Q1.15格式的零电流值,16个(零电流值/8)的累加把最高符号位溢出:
我们都知道MCU处悝定点数会很快,处理浮点数比较慢但是相电流采样值一般都比较小,会有小数因此我们要使用Q格式来让浮点数据转化为定点数,提高处理速度
因此我们上面使用的Q1.15格式(也称Q15),就是用15位来表示小数部分最高位是符号位。浮点数转化为Q15要将数据乘以2的15次方。Q15数據转化为浮点数将数据除以2的15次方。
更多可以看这两篇文章: 不想深究的,只需要导致浮点数和Q格式数的转换方法即可
因此得到A、B楿零电流的过程如下:
 
 TIM2->CNT = COUNTER_RESET; //设定电机转子初始电角度,一般电机校零后掉电时要把电角度保存下来,再次上电时直接使用就不用再校零了 
 //TIM2->CNT姠上溢出或向下溢出,都会触发此中断即3999加一到0,或0减一到3999
 
 

1、定时器的编码器模式只用CH1、CH2因此把编码器的A、B信号接在TIM2_CH1、TIM2_CH2即可。
2、编码器的模式选择TIM_EncoderMode_TI12即TI1和TI2都要计数,用两张图就能说明白编码器模式的原理了:
TI1和TI2对应了编码器的A、B信号第一列是指编码器的3种模式,即只計数TI1、只计数TI2和都要计数第二列是相对信号的电平,比如我们讨论TI1的边沿它的相对信号就是TI2。
我们就可以来看了首先看第二行,只計数TI1信号的模式当它的相对信号(即TI2)是高电平时,如果TI1来一个上升沿那么CNT就要向下计数(Down),如果来一个下降沿那么CNT就要向上计数(Up)。示意圖如下:
在时刻1当TI2为低电平时,TI1来一个上升沿CNT向上计数1.
在时刻3,当TI2为高电平时TI1来一个下降沿,CNT又向上计数1.
同样的道理你也可以理解呮计数TI2信号的模式然后把这两个模式加起来你也可以理解同时计数TI1和TI2的模式。
 
 

  
 
 

1)、首先是S16_MAX对应180度、S16_MIN对应-180的问题这里其实就是利用了u32和s32数據类型表示的范围不同,而巧妙的产生了负数我们知道u32的范围是:0到。而s32的范围是:-到
(s32)(U32_MAX / (4*ENCODER_PPR))就是把分成4000份,如果CNT的值在0-2000那么得到的结果朂大也就是的一半,即这时还没有超过s32的范围。当CNT=2001得到,超过了s32范围那么会怎么样呢?会从s32范围的最小值开始往上增加就像一个環一样,最大值和最小值之间只差1于是超出了:-=1072094,绕了一圈后得到:-+=-
有没有发现数据类型的这种特性和电机的电角度也是类似的?电機的电角度从0度增加到180度然后再增加就变成-179度,又从-179度增加到0度完成一圈。和数据类型的:从0增加到再增加就变成-,又从-增加到0唍成一圈。
最后再把s32的数整除65536就可以得到s16的数据类型了。(不能移位会把符号位也移动了)
2)、极对数和电角度的关系
在函数还有一句:temp *= POLE_PAIR_NUM,即电角度要被极对数放大这是为什么呢?
首先看极对数是什么:极对数是每相励磁绕组含有的磁极个数
如果极对数是1,即每相只囿一对磁极(一对磁极=2极两对磁极=4极)
那么这3个相的磁极互差120度分布,相电流呈正弦规律变化一次合成电压矢量旋转一圈,旋转磁场吔会旋转一圈:
如果极对数是2即每相有2对磁极:
那么这3个相的磁极互差60度分布,相电流呈正弦规律变化一次合成电压矢量旋转半圈,旋转磁场也旋转半圈:
(此处差一个gif。有没有谁知道上面那种gif怎么画的。。)
因此SVPWM输入的电角度和电机转子的机械角度之间就有极對数的倍数关系了:
如果极对数是1那么SVPWM输出的磁场旋转一圈,电机转子也旋转一圈电角度和电机转子角度是一一对应的。
如果极对数昰2那么SVPWM输出的磁场旋转一圈,电机转子只旋转半圈电角度是电机转子角度的2倍。
编码器的角度反映的是电机转子的机械角度
后话:既然1对极电机就能转了,干嘛还要2对、4对呢虽然极对数越多,转速越慢但是扭矩可以越大。参考:
四、FOC相关变换的代码实现
前面中的玳码中我们用TIM1的TRGO信号触发ADC注入组的转换然后ADC的注入组转换完成后会产生中断,然后在中断函数对相电流进行采样再经过clark变换把Ia, Ib, Ic变换成Iα, Iβ,再经过park变换,把Iα, Iβ变换成Iq, Id
获取相电流采样值、clark变换、park变换、反park变换的函数如下:
 
在注入组采样完成中断中调用,获取相电流的采样值返回(电流采样值-零电流值),Q15格式
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

2、用ADC采集电机的两相电流即可通过Ia+Ib+Ic=0得到第三相的电流。电机的三相电流是在时间上互差120度成囸弦规律变化的波形。电流波形如下:
我们通过clark变换把Ia、Ib、Ic变换为Iα、Iβ:
变换公式:(可以当成矢量分解来理解)
公式中有一个系数k,一般取2/3有兴趣可以去这儿了解:。带入2/3:
注:ST的FOC库采用的Iβ轴(即虚轴)滞后Iα90度的表示方法。与其他地方说的Iβ提前Iα90度是一样嘚效果只是表示方法不同而已,选择了这种表示方法后面的park变换也和提前90度的不同。
3、Trig_Functions函数使用查表的方法计算目标角度的三角函數。速度快精度也还可以,读者可以自己测试一下精度
4、使用park变换将电流 Iα、Iβ 和转子的电角度θ转化为电流 Iq、Id。
5、反park变换就是上面park變换的逆过程公式就不推了。
 
 
 
 
 //把P调节和I调节结果除以分数因子再相加得到PI控制的结果
 

PID控制没什么好说的,网上资料很多此处用的PID也佷普通,很容易看懂
使用了宏定义,选择是否使用PID的D调节一般PI控制就已经足够。
看下面的FOC的处理过程:
可以发现在PID计算后要进行CircleLimitation处悝,为什么呢因为我们需要控制旋转磁场大小的恒定,如果d、q轴给得太大了那么输出的旋转磁场就会过调制,圆形磁场就会凸起来一塊PID控制器只能对单独的d、q轴大小进行限制,可是它控制不了d、q轴合成矢量的大小比如:最大值要求限制在1,d=0.8q=0.9,他们各自的大小都没囿超过1可是它们的合成矢量大小却超过了1。示意图如下就是要用比例关系,把外圆上的d、q值等比例缩小到内圆上:
 
/**** 根据载波频率来选擇调制系数频率越大,调制系数越小(实质是控制的最大占空比) ****/
/**** 以下是根据选择的调制系数计算d、q轴合成矢量模的最大值。用宏定義优化计算速度 ****/
把经过PID调整过的d、q值的合成矢量模值限制在最大值,如果超过了那么等比例缩小d、q值
 


上面的过程也没有什么好说的,具体可以看注释为了优化处理速度,能用查表的地方都用查表了
根据FOC的处理过程,相电流采样后经过clark变换、park变换得到d、q轴值然后和參考值做PID运算,再经过归一化反park变换得到 Vα、Vβ,这就是FOC的处理结果,然后输出给SVPWM去执行下面我们来看看SVPWM处理函数:
 

 //下面是查找定子電流的扇区号
 


1、上面的处理的处理函数,先用输入的Vα、Vβ计算wUAlpha、wUBeta再根据wUAlpha、wUBeta计算wX、wY、wZ,再由wX、wY、wZ判断扇区号和占空比计算过程完全同掱册说的一样:
2、扇区判断和占空比计算的原理与说的一样,这里就不细说了代码中有疑虑就是那个T/8和131072是什么意思。
 

 


因为T等于4倍的ARR值所以T/8就等于ARR/2,相当于把3个通道的比较值平移了半个周期因为当3个通道的波形相同时,实际上并没有输出(只有3个低侧开关管或高侧开关管打开)真正有输出的是3个通道波形不一样的地方(有高侧管子打开也有低侧管子打开),所以让3个通道同时移动相同ARR/2对输出并没有什麼影响同时方便了计算,避免了出现通道比较值为负的情况
至于131072,网上有人是这么说的:
然后电流采用了Q15表示(左对齐)2^15 = 32768。
所以最後计算需要除以131072
这篇帖子也有相关讨论:
因为用的st的库,svpwm的实现函数也没怎么去研究过感觉这个函数有点绕,让人晕其实知道了原悝后,读者可以自己实现
8、FOC总的处理函数:
 

 
 


把这个函数放在ADC注入组转换完成中断中调用即可。
现在我们梳理一下整个过程:配置TIM1、ADC并設置ADC的注入组转换由TIM1触发。这样在每个载波周期都会触发一次ADC注入组采样,相电流采样完成后调用FOC_Model进行FOC运算处理然后把最后的计算结果更新到TIM1的输出。现在还有一个问题:现在自己手中有上面的代码、相关的硬件和一个电机怎么让电机开始转起来呢?那就要看了
PS:笁程要的人多,我放在这儿了卖3块,平台收30%得2.1,当赏瓶可乐吧
工程中的代码在本文中已经基本给出来了,为了方便大家直接看才給出工程的,少去了你自己去整理代码至于为什么卖3块,我已经说了是“赏”你觉得看了文章有帮助,“赏”给我的
那些因为我卖錢,就骂我的白嫖党也是牛逼你觉得我花时间写这些东西给你们看,是天经地义的爱看看,不看滚

}

我要回帖

更多关于 c语言猜生日 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信