先上 定时器 和 io 的设置
复制代码
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#include "includes.h" #define TMRNCLK (SYSCLK) /*---- S E T T I M 3 P W M O U T P U T ---- 【功能】:设置 tim3 使用 pc6 pc7 pc8 pc9输出,低电平有效, 当 tim3->cnt>= pwm占空比 就输出低电平 【参数】:**** 【返回】:**** 【说明】:**** --------------作者:卢杰西 2021年5月2日17:27:38--------------------------------*/ void SetTIM3PwmOutput() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //将tim3的ch 输出 重定位到 pc6 pc7 pc8 pc9 GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); SetPinState(GPIOC, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9, GPIO_Mode_AF_PP); //步进电机的方向控制 SetPinState(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15, GPIO_Mode_Out_PP); } /* //TIM3 CH1 PWM 输出设置 //PWM 输出初始化 //arr:自动重装值 //psc:时钟预分频数 */ /*---- T I M 3 T O M O T O R I N I T ---- 【功能】:初始化 tim3作为主定时器 给 tim2 输出脉冲,tim2作为计数定时器,tim2定义各个ch中断,对应4个电机 【参数】:**** 【返回】:**** 【说明】:**** --------------作者:卢杰西 2021年5月2日23:58:21--------------------------------*/ void Tim3ToMotorInit(INT32U frequency,INT8U enIrq) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; NVIC_InitTypeDef NVIC_InitStructure; // TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能 TIMx 外设 //设置住定时器TIM3 TIM_DeInit(TIM3); TIM_TimeBaseStructure.TIM_Period = PWM_Period-1; //设置自动重装载周期值 TIM_TimeBaseStructure.TIM_Prescaler =TMRNCLK/frequency/PWM_Period-1; //设置预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim 这里是 32M TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIMx TIM_ClearFlag(TIM3, TIM_FLAG_Update); TIM_ARRPreloadConfig(TIM3, ENABLE); //使能 TIMx 在 ARR 上的预装载寄存器 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //CH1 PWM2 模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值,系统没有启动前,默认低电平,让电机没有脉冲输入 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //发生对比后输出高电平 TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据指定的参数初始化外设 TIMx TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH1 预装载使能 TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据指定的参数初始化外设 TIMx TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH2 预装载使能 TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据指定的参数初始化外设 TIMx TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH3 预装载使能 TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根据指定的参数初始化外设 TIMx TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH4 预装载使能 SetTIM3PwmOutput(); TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //以TIM3的溢出 作为信号 #if 1 //设置从定时器TIM2 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能 TIMx 外设 TIM_DeInit(TIM2); TIM_TimeBaseStructure.TIM_Period = 65535; //设置自动重装载周期值 TIM_TimeBaseStructure.TIM_Prescaler =0; //设置预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化 TIMx TIM_ClearFlag(TIM2, TIM_FLAG_Update); TIM_ARRPreloadConfig(TIM2, ENABLE); //使能 TIMx 在 ARR 上的预装载寄存器 TIM_SelectInputTrigger(TIM2, TIM_TS_ITR2); //选择tim3的trgo输入 TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_External1); //选择trgi作为时钟输入 if(enIrq) { NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; /*溢出中断*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); /* 使能中断 */ } TIM_Cmd(TIM2, ENABLE); //使能 TIM3 #else if(enIrq) { NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel; /*溢出中断*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); /* 使能中断 */ } #endif TIM_Cmd(TIM3, ENABLE); //使能 TIM3 }
再将电机驱动封装为一个任务 用消息队列去发送操作命令
复制代码
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#include "includes.h" #define TIM3CEN PerpheralBit(TIM3->CR1,0) OS_EVENT *OSQMotor; S_MOTOR motor[4]={ {eMtStateStop,0,0,0,TIM_IT_CC1,&TIM3->CCR1,Bit2Addr32X(GPIOD->ODR,12),&TIM2->CCR1}, {eMtStateStop,0,0,0,TIM_IT_CC2,&TIM3->CCR2,Bit2Addr32X(GPIOD->ODR,13),&TIM2->CCR2}, {eMtStateStop,0,0,0,TIM_IT_CC3,&TIM3->CCR3,Bit2Addr32X(GPIOD->ODR,14),&TIM2->CCR3}, {eMtStateStop,0,0,0,TIM_IT_CC4,&TIM3->CCR4,Bit2Addr32X(GPIOD->ODR,15),&TIM2->CCR4}, }; /*---- S E N D M T M S G ---- 【功能】:**** 【参数】:index 电机编号 0-3 event :eMtCmdStop ... cnt 移动的距离 只有28位有效数字 【返回】:**** 【说明】:**** --------------作者:卢杰西 2021年5月4日13:21:38--------------------------------*/ void SendMtMsg(INT8U index,INT8U event,INT32S cnt) { INT32U msg=(cnt<<4)|(event<<2)|index; OSQPost(OSQMotor,(void*)msg); } /*---- G E T M O T O R P O S ---- 【功能】:获取电机的 当前位置 【参数】:**** 【返回】:**** 【说明】:**** --------------作者:卢杰西 2021年5月4日1:16:20--------------------------------*/ INT32S GetMotorPos(INT8U i) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif INT32S ret; OS_ENTER_CRITICAL(); if(motor[i].state==eMtStateAdd) ret=motor[i].pos_base+TIM2->CNT; else if(motor[i].state==eMtStateDec) ret=motor[i].pos_base-TIM2->CNT; else ret=motor[i].pos; OS_EXIT_CRITICAL(); return ret; } /*---- S T O P M O T O R ---- 【功能】:停止电机转动 【参数】:**** 【返回】:**** 【说明】:停止电机转动 --------------作者:卢杰西 2021年5月4日0:42:19--------------------------------*/ void StopMotor(INT8U i) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif if(motor[i].state==eMtStateAdd) { TIM3CEN=0; //pwm占空比设置为0,不输出脉冲,保持低电平 OS_ENTER_CRITICAL(); *motor[i].pwm=0; //关闭脉冲输出 motor[i].pos=motor[i].pos_base+TIM2->CNT; TIM_ITConfig(TIM2,motor[i].irq,DISABLE); /* 关闭中断 */ motor[i].state=eMtStateStop; OS_EXIT_CRITICAL(); TIM3CEN=1; } else if(motor[i].state==eMtStateDec) { TIM3CEN=0; //pwm占空比设置为0,不输出脉冲,保持低电平 OS_ENTER_CRITICAL(); *motor[i].pwm=0; //关闭脉冲输出 motor[i].pos=motor[i].pos_base-TIM2->CNT; TIM_ITConfig(TIM2,motor[i].irq,DISABLE); /* 关闭中断 */ motor[i].state=eMtStateStop; OS_EXIT_CRITICAL(); TIM3CEN=1; } TIM_ClearITPendingBit(TIM2, motor[i].irq); } /*---- M O T O R R R U N ---- 【功能】: 【参数】:**** 【返回】:**** 【说明】:电机移动到指定位置 --------------作者:卢杰西 2021年5月4日0:47:06--------------------------------*/ void MotorrRunTo(INT8U i,INT32S dst) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif INT32S cur; TIM3CEN=0; //pwm占空比设置为0,不输出脉冲,保持低电平 OS_ENTER_CRITICAL(); if(motor[i].state==eMtStateAdd) cur=motor[i].pos_base+TIM2->CNT; else if(motor[i].state==eMtStateDec) cur=motor[i].pos_base-TIM2->CNT; else cur=motor[i].pos; if(cur==dst) { *motor[i].pwm=0; //关闭脉冲输出 motor[i].pos=cur; TIM_ITConfig(TIM2,motor[i].irq,DISABLE); /* 关闭中断 */ motor[i].state=eMtStateStop; } else if(cur<dst) { *motor[i].pwm=PWM_Period/2; *motor[i].dir=eMtStateAdd; //正转 motor[i].state=eMtStateAdd; motor[i].dst=dst; motor[i].pos_base=cur-TIM2->CNT; //base 位置 if(dst-motor[i].pos_base<=65536) { TIM_ClearITPendingBit(TIM2, motor[i].irq); *motor[i].tmr=dst-motor[i].pos_base; TIM_ITConfig(TIM2,motor[i].irq,ENABLE); /* 启动中断 */ } else TIM_ITConfig(TIM2,motor[i].irq,DISABLE); /* 关闭中断 */ } else if(cur>dst) { *motor[i].pwm=PWM_Period/2; *motor[i].dir=eMtStateDec; //正转 motor[i].state=eMtStateDec; motor[i].dst=dst; motor[i].pos_base=cur+TIM2->CNT; //base 位置 if(motor[i].pos_base-dst<=65536) { TIM_ClearITPendingBit(TIM2, motor[i].irq); *motor[i].tmr=motor[i].pos_base-dst; TIM_ITConfig(TIM2,motor[i].irq,ENABLE); /*启动中断*/ } else TIM_ITConfig(TIM2,motor[i].irq,DISABLE); /*关闭中断*/ } OS_EXIT_CRITICAL(); TIM3CEN=1; //pwm占空比设置为0,不输出脉冲,保持低电平 } /*---- M O T O R T A S K ---- 【功能】:电机驱动任务, 【参数】:**** 【返回】:**** 【说明】:所有电机动作前,先关闭TIM3的cen,电机操作后 再重新打开cen --------------作者:卢杰西 2021年5月3日23:18:48--------------------------------*/ void MotorTask(void *pdata) { INT8U i,event; INT32U msg; INT32S cnt,bak; msg=(INT32U)pdata; CREATE_SMSG(OSQMotor, 12); Tim3ToMotorInit(10000, 1); do{ msg=(INT32U)OSQPend(OSQMotor,0,&i); i=msg&0x03; event=(msg>>2)&0x03; cnt=msg>>4; if(msg&0x80000000) cnt|=0xF0000000; switch(event) { case eMtCmdStop: StopMotor(i); break; case eMtCmdStopSet: StopMotor(i); motor[i].pos=cnt; break; case eMtCmdRun: bak=GetMotorPos(i); if((bak>0 && cnt>0) && (cnt+bak)<0) cnt=0x7FFFFFFF; else if((bak<0 && cnt<0) && (cnt+bak)>0) cnt=0-0x7FFFFFFF; else cnt+=bak; case eMtCmdRunTo: MotorrRunTo(i,cnt); break; } }while(1); } /*---- T I M 2 _ I R Q H A N D L E R ---- 【功能】:计算脉冲数的定时器中断处理 【参数】:**** 【返回】:**** 【说明】:溢出中断 电机更新 base计数 当base计数 和 dst 的差距<=65536 就可以开 ccx 中断,精确停止 --------------作者:卢杰西 2021年5月4日13:23:44--------------------------------*/ void TIM2_IRQHandler (void) { INT8U i; OSIntEnter(); if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); for(i=0;i<GetItemSum(motor);i++) { if(motor[i].state==eMtStateAdd) { motor[i].pos_base+=65536; if(motor[i].dst-motor[i].pos_base<=65536 && motor[i].dst!=motor[i].pos_base) { TIM_ClearITPendingBit(TIM2, motor[i].irq); *motor[i].tmr=motor[i].dst-motor[i].pos_base; TIM_ITConfig(TIM2,motor[i].irq,ENABLE); /* 启动中断 */ } } else if(motor[i].state==eMtStateDec) { motor[i].pos_base-=65536; if(motor[i].pos_base-motor[i].dst<=65536 && motor[i].dst!=motor[i].pos_base) { TIM_ClearITPendingBit(TIM2, motor[i].irq); *motor[i].tmr=motor[i].pos_base-motor[i].dst; TIM_ITConfig(TIM2,motor[i].irq,ENABLE); /* 启动中断 */ } } } } for(i=0;i<GetItemSum(motor);i++) { if (TIM_GetITStatus(TIM2, motor[i].irq) != RESET && TIM_GetITStatus(TIM2, motor[i].irq)) { SendMtMsg(i,eMtCmdStop,0); TIM_ClearITPendingBit(TIM2, motor[i].irq); } } OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */ }
通过命令
SendMtMsg(0, eMtCmdRun, 3600); //相对移动
SendMtMsg(0, eMtCmdRunTo, 3600); //绝对运动
SendMtMsg(0, eMtCmdStop, 3600); //停止运动
最后
以上就是幸福草莓最近收集整理的关于stm32 使用 TIM3 输出脉冲 TIM2 进行脉冲计数的全部内容,更多相关stm32内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复