历史上的今天
返回首页

历史上的今天

今天是: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信号:

推荐阅读

史海拾趣

Comtech AHA Corp公司的发展小趣事

品质是Comtech AHA Corp的生命线。公司始终坚持严格的品质管理,从原材料采购到生产流程,再到成品检验,每一个环节都严格把关。正是这种对品质的执着追求,使得Comtech AHA Corp的产品在市场上赢得了良好的口碑。许多知名企业纷纷与Comtech AHA Corp建立长期合作关系,进一步推动了公司的发展。

ddm hopt + schuler GmbH & Co KG公司的发展小趣事

ddm hopt + schuler GmbH & Co KG公司自创立之初,就专注于电子制造设备的研发与生产。在20世纪90年代,公司成功研发出一款具有革命性意义的自动化生产线,极大地提高了电子产品的生产效率和质量。这一技术突破迅速赢得了市场的认可,公司开始在全球范围内扩张业务,与多家知名电子品牌建立了长期合作关系。

BELLING LEE公司的发展小趣事

在激烈的市场竞争中,BELLING LEE公司始终坚持品质至上的原则。公司从原材料采购、生产制造到售后服务都严格把关,确保每一款产品都能达到高品质标准。这种对品质的执着追求赢得了客户的信任和好评,也为公司赢得了良好的口碑和品牌形象。

Danube Enterprise Co Ltd公司的发展小趣事

在稳固了国内市场地位之后,Danube开始将目光投向了全球市场。他们通过设立海外办事处、与当地企业合作等方式,积极开拓国际市场。Danube的产品凭借其卓越的品质和创新的设计,逐渐在国际市场上崭露头角。同时,公司还根据不同国家和地区的市场需求,推出了定制化的产品和服务,进一步增强了其市场竞争力。这些努力让Danube在全球电子行业中逐渐崭露头角,成为了一家备受瞩目的企业。

屹晶微(EG)公司的发展小趣事

屹晶微的创始人黄米龙,原本在发电厂从事电气运营工作长达八年。这段经历让他对电子领域有了深入的了解和浓厚的兴趣。然而,他并没有满足于现状,而是看到了中国芯片产业的巨大潜力和发展空间。于是,在2007年,他毅然决定从发电厂辞职,利用自己的积蓄和借来的资金,在台州创立了屹晶微电子有限公司。

在创立初期,屹晶微面临着资金短缺、技术落后和市场竞争激烈的困境。但黄米龙凭借对电子行业的深刻理解和坚定的信念,带领团队克服了种种困难。他们不断引进先进技术和设备,加强研发力量,提升产品质量。经过几年的努力,屹晶微逐渐在芯片设计领域崭露头角,并成功推出了多款具有自主知识产权的芯片产品。

富芯森美(FUXINSEMI)公司的发展小趣事

随着技术实力的不断提升,富芯森美开始积极拓展市场。公司凭借优质的产品和专业的服务,成功打入消费类电子、安防、工控、汽车电子等多个领域。同时,富芯森美还注重品牌建设,通过参加国内外知名展会、举办技术研讨会等方式,不断提升品牌知名度和影响力。这些努力使得富芯森美在电子行业中逐渐崭露头角,成为行业内的佼佼者。

问答坊 | AI 解惑

【藏书阁】半导体集成电路(上、下册)

书名: 半导体集成电路 (上册) 作者: 上海无线电十九厂 复旦大学四一工厂 出版社: 上海人民出版社 出版日期: 1971年04月第1版 出版地: 上海 定价: 0.76 [ 本帖最后由 wzt 于 2010-2-23 15:52 编辑 ]…

查看全部问答>

求教关于STTL反相器电路

帖子发到别的板块去了,请见谅!! http://topic.eeworld.net/u/20090122/23/72329197-01f2-41b6-8239-7dfb8466a18f.html…

查看全部问答>

320240液晶

请前辈推荐320240液晶显示模块!…

查看全部问答>

wince 中如何通过检查注册表来判断u盘是否已经插上呢?

wince 中如何通过检查注册表来判断u盘是否已经插上呢?…

查看全部问答>

职位:硬件研发经理!

我是北京的一家猎头公司,目前有一个硬件研发经理的职位向推荐给大家,此职位要求从事仪表或电力相关行业硬件设计、嵌入式开发、自动化控制的经验,个人发展,待遇都很不错,有意向的朋友还请联系我:010-59081065,MSN:xiaomichong_happy@hotmail ...…

查看全部问答>

IBM移动硬盘问题~!(急)

大家好,我有一个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 ...…

查看全部问答>

stm32外扩sram读取数据问题

我的sram用的是is61lv25616al 256k的。我存储的数据宽度是8bit,读数据的时候发现一个问题,它会以4000多个数据为单位反复7次再接着读下面的。。。。纠结了快两天了找不出原因。请教有没有人遇到数据重复的 问题?怎么解决?…

查看全部问答>

【MSP430共享】基于模糊神经网络的输液监控系统设计

以 MS P 4 3 0   M C U为控制核心 , 结合输液传感器、 电动执行器、 液晶显示、 键盘等 , 实现 了对输液过程的 自动监控。由于输液系统是一个非线性、 时变、 滞后 的复杂控制对 象. 采用传统的控制策略难以取得 良好的实时监控效果。 ...…

查看全部问答>

焊了个51的板子,除GND脚所有都是高电平,求帮助

程序在别的板子上测过了,木有问题。引脚什么的也都是通的,现在想着是不是晶振电路的问题,要不就是复位电路? 晶振的38,39脚测出2v,不变。对了,31脚的EA用接高电平么?我接不接效果一样。。。…

查看全部问答>