历史上的今天
今天是:2025年06月29日(星期日)
2021年06月29日 | 单片机异常复位后如何保存变量数据
2021-06-29 来源:eefocus
接着上篇,先解释一下为什么会出现“共振”现象,如下图:

假如A1的占空比为25%,B2的占空比为10%,C2的占空比也为10%,我一开始想象的A1和B1之间的信号强度应该是:
25% x 10% = 2.5%
但是实际远不是这么回事,假如B2的高电平时间范围正好都落在了A1的高电平时间范围中,那么A1到B2的信号的实际占空比就是B2信号的占空比10%。但是如果 B2的高电平时间范围没有完全都落在了A1的高电平时间范围中或者完全没有落在A1的高电平时间范围中的话,A1到B2的有效信号宽度是A1和B2的信号中高电平重叠部分的宽度。比如C2的信号,高电平信号完全落在了A1信号高电平的外部,也就是A1到C2之间根本没有重叠的部分,不会有电流产生,即使A1和C2的占空都比大于0。
为了解决这个问题,我的做法是将所有PWM通道初始化之后先不要使能定时器,而是在初始化完所有定时器之后再统一进行定时器的使能,这样几个定时器的使能时间差在几个us的级别,甚至更小(CPU为48MHz主频,执行这几条指令耗时很低,而且将全局中断关闭,防止有中断打断该过程),而PWM信号的频率一般是20KHz,周期为50us,这样可以让PWM信号的初相尽可能一样,这样就能让PWM信号的重叠区域最大,示例程序如下:
......
TIM1_PWM_Init(255 - 1,10); //48MHz / 10 / 255 = 18.8KHz
TIM3_PWM_Init(255 - 1,10);
TIM14_PWM_Init(255 - 1,10);
......
__disable_irq(); //关闭全局中断
int tmp1,tmp2,tmp3;
tmp1 = TIM1->CR1 | TIM_CR1_CEN;
tmp2 = TIM3->CR1 | TIM_CR1_CEN;
tmp3 = TIM14->CR1 | TIM_CR1_CEN;
TIM1->CR1 = tmp1;
TIM3->CR1 = tmp2;
TIM14->CR1 = tmp3;
__enable_irq(); //打开全局中断
测试一下A1、B1、C1的波形相位问题:

可以看出来A1和B1的相位差0.25u(因为我的逻辑分析仪的采样率是4MHz,最小分辨率0.25us,所以实际的大小可能是小于0.25us的),已经很小了,但是B1和C1没有相位差,因为B1和C1都是TIM3输出的PWM,肯定没有误差。可以猜测B1和C2差不多也误差0.25us以下,属于可接受范围了,可以使用PWM信号来控制电流大小。实在是缺示波器。
下面为了使得PWM信号派上用场,这里对三相波形的细分。三相驱动信号原图为:

我们将电流的瞬变改成渐变,如下图的紫色、蓝色、绿色三根:

为了提高驱动电流,将t0到t5这6个阶段拆分成t0_1、t0_2、t1_1、t1_2、t2_1、t2_2、t3_1、t3_2、t4_1、t4_2、t5_1、t5_2这12个阶段,每一个单独的阶段中只有一相信号处于渐变状态,其余两相处于满状态(占空比100%),这样就提高了总的电流和扭矩。下图为扩展后的波形图(PS零水平,手绘):

12个阶段的A、B、C相的状态表也在上图中写出来了,根据这个状态表写每个阶段的程序即可:
void t0_1(void)
{
// printf("A:0->1 B:-1 C:1rn");
*A1 = 0;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = MAX_PWM;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*A1 = i;
delay_us(INTERVAL);
}
}
void t0_2(void)
{
// printf("A:1 B:-1 C:1->0rn");
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = MAX_PWM;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*C1 = MAX_PWM - i;
delay_us(INTERVAL);
}
}
void t1_1(void)
{
// printf("A:1 B:-1 C:0->-1rn");
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = 0;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*C2 = i;
delay_us(INTERVAL);
}
}
void t1_2(void)
{
// printf("A:1 B:-1->0 C:-1rn");
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = 0;
*C2 = MAX_PWM;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*B2 = MAX_PWM - i;
delay_us(INTERVAL);
}
}
void t2_1(void)
{
// printf("A:1 B:0->1 C:-1rn");
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*B1 = i;
delay_us(INTERVAL);
}
}
void t2_2(void)
{
// printf("A:1->0 B:1 C:-1rn");
*A1 = MAX_PWM;
*A2 = 0;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*A1 = MAX_PWM - i;
delay_us(INTERVAL);
}
}
void t3_1(void)
{
// printf("A:0->-1 B:1 C:-1rn");
*A1 = 0;
*A2 = 0;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*A2 = i;
delay_us(INTERVAL);
}
}
void t3_2(void)
{
// printf("A:-1 B:1 C:-1->0rn");
*A1 = 0;
*A2 = MAX_PWM;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*C2 = MAX_PWM - i;
delay_us(INTERVAL);
}
}
void t4_1(void)
{
// printf("A:-1 B:1 C:0->1rn");
*A1 = 0;
*A2 = MAX_PWM;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*C1 = i;
delay_us(INTERVAL);
}
}
void t4_2(void)
{
// printf("A:-1 B:1->0 C:1rn");
*A1 = 0;
*A2 = MAX_PWM;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = MAX_PWM;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*B1 = MAX_PWM - i;
delay_us(INTERVAL);
}
}
void t5_1(void)
{
// printf("A:-1 B:0->-1 C:1rn");
*A1 = 0;
*A2 = MAX_PWM;
*B1 = 0;
*B2 = 0;
*C1 = MAX_PWM;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*B2 = i;
delay_us(INTERVAL);
}
}
void t5_2(void)
{
// printf("A:-1->0 B:-1 C:1rn");
*A1 = 0;
*A2 = MAX_PWM;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = MAX_PWM;
*C2 = 0;
int i;
for(i=0;i<=MAX_PWM;i++)
{
*A2 = MAX_PWM - i;
delay_us(INTERVAL);
}
}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
主程序按顺序调用这12个函数:
登录后复制
//设置所有桥臂为无输出。注意IO_X1和IO_X2信号不可以同时为高,
//否则会导致桥臂短路,容易烧坏MOS管,同时在程序中最好先将为0的
//信号先设置为0,然后再设置不为0的信号,这样可以避免短路。
*A1 = 0;
*A2 = 0;
*B1 = 0;
*B2 = 0;
*C1 = 0;
*C2 = 0;
#define INTERVAL 10 //PWM上升下降间隔时间
#define MAX_PWM 255
//处于t5状态,并维持一段时间,保证可靠处于t5状态
printf("Readyrn");
{ //t5:CB
printf("t5:CBrn");
*A1 = 0;
*A2 = 0;
*C1 = MAX_PWM;
*C2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
}
delay_ms(200);
while(1)
{
t0_1();// printf("0_1rn"); delay_ms(2000);
t0_2();// printf("0_2rn"); delay_ms(2000);
t1_1();// printf("1_1rn"); delay_ms(2000);
t1_2();// printf("1_2rn"); delay_ms(2000);
t2_1();// printf("2_1rn"); delay_ms(2000);
t2_2();// printf("2_2rn"); delay_ms(2000);
t3_1();// printf("3_1rn"); delay_ms(2000);
t3_2();// printf("3_2rn"); delay_ms(2000);
t4_1();// printf("4_1rn"); delay_ms(2000);
t4_2();// printf("4_2rn"); delay_ms(2000);
t5_1();// printf("5_1rn"); delay_ms(2000);
t5_2();// printf("5_2rn"); delay_ms(2000);
}
主程序按顺序调用这12个函数:
//设置所有桥臂为无输出。注意IO_X1和IO_X2信号不可以同时为高,
//否则会导致桥臂短路,容易烧坏MOS管,同时在程序中最好先将为0的
//信号先设置为0,然后再设置不为0的信号,这样可以避免短路。
*A1 = 0;
*A2 = 0;
*B1 = 0;
*B2 = 0;
*C1 = 0;
*C2 = 0;
#define INTERVAL 10 //PWM上升下降间隔时间
#define MAX_PWM 255
//处于t5状态,并维持一段时间,保证可靠处于t5状态
printf("Readyrn");
{ //t5:CB
printf("t5:CBrn");
*A1 = 0;
*A2 = 0;
*C1 = MAX_PWM;
*C2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
}
delay_ms(200);
while(1)
{
t0_1();// printf("0_1rn"); delay_ms(2000);
t0_2();// printf("0_2rn"); delay_ms(2000);
t1_1();// printf("1_1rn"); delay_ms(2000);
t1_2();// printf("1_2rn"); delay_ms(2000);
t2_1();// printf("2_1rn"); delay_ms(2000);
t2_2();// printf("2_2rn"); delay_ms(2000);
t3_1();// printf("3_1rn"); delay_ms(2000);
t3_2();// printf("3_2rn"); delay_ms(2000);
t4_1();// printf("4_1rn"); delay_ms(2000);
t4_2();// printf("4_2rn"); delay_ms(2000);
t5_1();// printf("5_1rn"); delay_ms(2000);
t5_2();// printf("5_2rn"); delay_ms(2000);
}
这里的INTERVAL是上升延时,和上篇文章中的不是一个含义。调整INTERVAL的大小可以改变转速,程序运行的不错,电机比之前运行丝滑很多,和某巧克力一样。
程序可以停在12个阶段中的任意一个阶段中的任意一个状态,所以可以实现和步进电机一样的步进控制,调大INTERVAL到1000以以上就能看出电机慢慢的转动的现象了,但是不如步进电机,老是会有“突变”的现象,可能就是无刷电机结构问题导致的,因为无刷电机一开始就没这么用的......
再来改一下程序,如下:
void go_stage(int stage)
{
if(stage == 0)
{
*A1 = 0;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = MAX_PWM;
*C2 = 0;
}
else if(stage == 1)
{
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = MAX_PWM;
*C2 = 0;
}
else if(stage == 2)
{
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = 0;
*C2 = 0;
}
else if(stage == 3)
{
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = 0;
*C2 = MAX_PWM;
}
else if(stage == 4)
{
*A1 = MAX_PWM;
*A2 = 0;
*B1 = 0;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
}
else if(stage == 5)
{
*A1 = MAX_PWM;
*A2 = 0;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
}
else if(stage == 6)
{
*A1 = 0;
*A2 = 0;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
}
else if(stage == 7)
{
*A1 = 0;
*A2 = MAX_PWM;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = MAX_PWM;
}
else if(stage == 8)
{
*A1 = 0;
*A2 = MAX_PWM;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = 0;
*C2 = 0;
}
else if(stage == 9)
{
*A1 = 0;
*A2 = MAX_PWM;
*B1 = MAX_PWM;
*B2 = 0;
*C1 = MAX_PWM;
*C2 = 0;
}
else if(stage == 10)
{
*A1 = 0;
*A2 = MAX_PWM;
*B1 = 0;
*B2 = 0;
*C1 = MAX_PWM;
*C2 = 0;
}
else if(stage == 11)
{
*A1 = 0;
*A2 = MAX_PWM;
*B1 = 0;
*B2 = MAX_PWM;
*C1 = MAX_PWM;
*C2 = 0;
}
}
void main(void)
{
......
//设置所有桥臂为无输出。注意IO_X1和IO_X2信号不可以同时为高,
//否则会导致桥臂短路,容易烧坏MOS管,同时在程序中最好先将为0的
//信号先设置为0,然后再设置不为0的信号,这样可以避免短路。
*A1 = 0;
*A2 = 0;
*B1 = 0;
*B2 = 0;
*C1 = 0;
*C2 = 0;
#define INTERVAL 10 //PWM上升下降间隔时间
#define MAX_PWM 255
printf("Readyrn");
stage = 0;
go_stage(stage);
delay_ms(200);
direction = 0; //控制转动方向
stage = 0; //当前阶段
offset = 0; //阶段中偏移
while(1)
{
if(direction == 0) //顺时针
{
offset++;
if(offset == MAX_PWM + 1) //换相
{
offset= 0;
stage++;
if(stage == 12)
stage = 0;
go_stage(stage);
}
}
else
{
if(offset == 0) //换相
{
offset= 255;
if(stage == 0)
stage = 11;
else
stage--;
go_stage(stage);
}
else
offset--;
}
switch(stage)
{
case 0 :*A1 = offset; break;
case 1 :*C1 = MAX_PWM - offset; break;
case 2 :*C2 = offset; break;
case 3 :*B2 = MAX_PWM - offset; break;
case 4 :*B1 = offset; break;
case 5 :*A1 = MAX_PWM - offset; break;
case 6 :*A2 = offset; break;
case 7 :*C2 = MAX_PWM - offset; break;
case 8 :*C1 = offset; break;
case 9 :*B1 = MAX_PWM - offset; break;
case 10 :*B2 = offset; break;
case 11 :*A2 = MAX_PWM - offset; break;
}
delay_us(INTERVAL);
}
}
通过调整direction和INTERVAL的值可以修改转动方向和转动速度,改变MAX_PWM可以调整电流大小。抓取一下波形看看6个通道的PWM信号的12个阶段,其中白色的部分是PWM信号:
史海拾趣
|
书名: 半导体集成电路 (上册) 作者: 上海无线电十九厂 复旦大学四一工厂 出版社: 上海人民出版社 出版日期: 1971年04月第1版 出版地: 上海 定价: 0.76 [ 本帖最后由 wzt 于 2010-2-23 15:52 编辑 ]… 查看全部问答> |
|
帖子发到别的板块去了,请见谅!! http://topic.eeworld.net/u/20090122/23/72329197-01f2-41b6-8239-7dfb8466a18f.html… 查看全部问答> |
|
我是北京的一家猎头公司,目前有一个硬件研发经理的职位向推荐给大家,此职位要求从事仪表或电力相关行业硬件设计、嵌入式开发、自动化控制的经验,个人发展,待遇都很不错,有意向的朋友还请联系我:010-59081065,MSN:xiaomichong_happy@hotmail ...… 查看全部问答> |
|
大家好,我有一个IBM的移动硬盘,昨天一直好好的,我插进电脑时,发现了3个EXE文件,我就随手删掉了`还把移动硬盘里的Recycled删了``然后我没停止移动硬盘,就直接把移动硬盘从USB上取了出来```当我今天用的时候,发现电脑提示找到新硬件以后,我打开就 ...… 查看全部问答> |
|
32-bitSTM32通过16-bit总线连接LCD,地址0x60000002对应A0是? LCD通过FSMC映射到地址0x6C000000,A0=0时选中LCD的Index或状态寄存器、A0=1时选中控制寄存器,文档里有:A0=0时地址为0x6C000000,A0=1时地址为0x6C000002,我的问题是: A0=1时,地址最低位是0,那么应该是0x6C000001,为什么是0x6C000002 ...… 查看全部问答> |
|
我的sram用的是is61lv25616al 256k的。我存储的数据宽度是8bit,读数据的时候发现一个问题,它会以4000多个数据为单位反复7次再接着读下面的。。。。纠结了快两天了找不出原因。请教有没有人遇到数据重复的 问题?怎么解决?… 查看全部问答> |
|
以 MS P 4 3 0 M C U为控制核心 , 结合输液传感器、 电动执行器、 液晶显示、 键盘等 , 实现 了对输液过程的 自动监控。由于输液系统是一个非线性、 时变、 滞后 的复杂控制对 象. 采用传统的控制策略难以取得 良好的实时监控效果。 ...… 查看全部问答> |
|
程序在别的板子上测过了,木有问题。引脚什么的也都是通的,现在想着是不是晶振电路的问题,要不就是复位电路? 晶振的38,39脚测出2v,不变。对了,31脚的EA用接高电平么?我接不接效果一样。。。… 查看全部问答> |




