利用STM32F103精确控制步进电机
利用STM32F103精确控制步进电机
一、用到的元器件
STM32F103C8T6
42步进电机(42SHDC4040-17B)
TB6600电机驱动器升级版
二、42步进电机
1.步进电机的基本知识
(1)拍数——每一次循环所包含的通电状态数(电机转过一个齿距角所需脉冲数)
(2)单拍制分配方式——状态数=相数
(3)双拍制分配方式——状态数=相数的两倍
(4)步距角 ——步进机通过一个电脉冲转子转过的角度
- N:一个周期的运行拍数
Zr:转子齿数
拍数:N=km
m:相数
k=1单拍制
k=2双拍制
(5)转速
(6)角度细分的原理
- 电磁力的大小与绕组通电电流的大小有关。
- 当通电相的电流并不马上升到位,而断电相的电流也非立即降为0时,它们所产生的磁场合力,会使转子有一个新的平衡位置,这个新的平衡位置是在原来的步距角范围内。
2. 42步进电机参数
无法查找到42SHDC4040-17B型号的详细资料,以通用42步进电机为例:
步距角 1.8°
步距角精度 ±5%
相数 2相
励磁方式 混合式
转子齿数 50
拍制 双拍制
其他参数:无
由步距角=1.8°推算出转子齿数为50,拍制为双拍制
3. 42步进电机速度与角度控制
电机的转速与脉冲频率成正比,电机转过的角度与脉冲数成正比。所以控制脉冲数和脉冲频率就可以精确调速。
理论上步进电机转速 = 频率 * 60 /((360/T)*x)
w=f∗60(360°T×x)w= \frac{f*60}{(\frac {360°}{T}\times x)} w=(T360°×x)f∗60
- 转速单位: 转/ 分
- 频率单位:赫兹
- x 细分倍数
- T 步距角
例如,在本实验中,32细分;频率72000 赫兹;步距角1.8°;套用公式72000∗60((360/1.8)∗32)=112.5\frac{72000*60}{((360/1.8)*32)}=112.5((360/1.8)∗32)72000∗60=112.5rad/ min,即1.875 rad/s.
三、TB6600电机驱动器升级版参数
TB6600步进电机驱动器升级版是一款专业的两相步进电机驱动,可实现正反转控制。通过S1,S2,S3 3位拨码开关选择7档细分控制(1,2/A,2/B,4,8,16,32,),通过S4,S5,S6 3位拨码开关选择8 档电流控制(0.5A,1A,1.5A,2A,2.5A,2.8A,3.0A,3.5A)。适合驱动57,42 型两相、四相混合式步进电机。
1.信号输入端
PUL+:脉冲信号输入正。( CP+ )
PUL-:脉冲信号输入负。( CP- )
DIR+:电机正、反转控制正。
DIR-:电机正、反转控制负。
EN+:电机脱机控制正。
EN-:电机脱机控制负。
- 共阳极接法:分别将PUL+,DIR+,EN+连接到控制系统的电源上, 如果此电源是+5V则可直接接入,如果此电源大于+5V,则须外部另加限流电阻R,保证给驱动器内部光藕提供8—15mA 的驱动电流。
- 共阴极接法:分别将 PUL-,DIR-,EN-连接到控制系统的地端;脉冲输入信号通过PUL+接入,方向信号通过DIR+接入,使能信号通过EN+接入。若需限流电阻,限流电阻R的接法取值与共阳极接法相同。
- 注:EN端可不接,EN有效时电机转子处于自由状态(脱机状态),这时可以手动转动电机转轴。
2.电机绕组连接
A+:连接电机绕组A+相。
A-:连接电机绕组A-相。
B+:连接电机绕组B+相。
B-:连接电机绕组B-相。
3.电源电压连接
VCC:电源正端“+”
GND:电源负端“-”
注意:DC直流范围:9-32V。不可以超过此范围,否则会无法正常工作甚至损坏驱动器.
4.拨码开关
Micro step | 脉冲/转 | S1 | S2 | S3 |
---|---|---|---|---|
NC | NC | ON | ON | ON |
1 | 200 | ON | ON | OFF |
2/A | 400 | ON | OFF | ON |
2/B | 400 | OFF | ON | ON |
4 | 800 | ON | OFF | OFF |
8 | 1600 | OFF | ON | OFF |
16 | 3200 | OFF | OFF | ON |
32 | 6400 | OFF | OFF | OFF |
电流大小设定
Current(A) | S4 | S5 | S6 |
---|---|---|---|
0.5 | ON | ON | ON |
1.0 | ON | OFF | ON |
1.5 | ON | ON | OFF |
2.0 | ON | OFF | OFF |
2.5 | OFF | ON | ON |
2.8 | OFF | OFF | ON |
3.0 | OFF | ON | OFF |
3.5 | OFF | OFF | OFF |
三、STM32F103
------说明:引脚部分在文章末尾有解释--------
1.引脚连接
A 0——PUL+
A 3——KEY1——V3
A12——DIR+
A11——EAN+
GND——EAN- ——KEY0
2.引脚功能
A0控制电机转速
A3控制按键
A9
A11
A11控制电机是否为锁死状态
A12控制电机正反转
3.定时器
1.本实验利用定时器TIM2和定时器TIM3构造一个主从定时器,TIM2作为主定时器控制电机的转速,TIM3作为从定时器控制电机的转动角度。
2.电机的转速和转角还与驱动器自身的细分数有关,但是驱动器细分数是通过影响电机的步距角来影响转速和转角,而TIM2和TIM3是控制步进电机的频率和脉冲数来控制转速转角
3.电机的转速和角度与定时器的关系(在不考虑电机自身的细分数下)
设TIM2的定时周期(即重装值)为nPDTemp2,预分频值为OCPolarity2
TIM3的定时周期(即重装值)为nPDTemp3,预分频值为OCPolarity3,
则单片机产生一个脉冲所需要的时间为:
T=(nPDTemp2+1)72MHzOCPolarity2+1T= \frac{(nPDTemp2+1)}{ \frac{72MHz}{OCPolarity2+1}}T=OCPolarity2+172MHz(nPDTemp2+1)
本实验中设TIM2的定时周期nPDTemp2=72000/5000-1,预分频值OCPolarity2=999,TIM3的定时周期nPDTemp3=6399,预分频值OCPolarity3为0。即T=72000500072×106999+1=0.0002sT= \frac{\frac{72000}{5000}}{ \frac{72\times 10^6}{999+1}}=0.0002sT=999+172×106500072000=0.0002s
定时器共产生nPDTemp3+1=6400个脉冲,电机转过的角度为6400*1.8°=11520°,即电机转了32圈。
转动速度
w=1.8°/360°T=25(rad/s)w = \frac{1.8°/360°}{T}=25 (rad/s)w=T1.8°/360°=25(rad/s)
4.在32细分的情况下电机1rad/s和转1°需要的重装值为nPDTemp2=11.25,nPDTemp3=17.7778。
四、程序实现
1.main.c程序
#include "main.h"
#include "sys.h"
#include "usart1.h"
#include "delay.h"
#include "math.h"u16 t;
u16 len; //接收到的数据长度
u16 times=0;
char receive_data[60]; //接收到的字符
char state; //电机正反转标志位0正转,1反转
int speed,angle; //旋转速度,角度
int a=0; //判断是否接收到数据
int r,data=0; //用于数据转换
int type; //转换后的数据
extern u16 USART_RX_STA;/*************************** 函数名:delay* 描述 :延时函数* 输入 :无 * 输出 :无* 返回值:无
****************************/void delay()//延时{int i,j;for(i=0;i<2000;i++)for(j=0;j<1000;j++);}/*************************** 函数名:Waiting_receptio* 描述 :等待串口接收数据* 输入 :无 * 输出 :无* 返回值:无
****************************/
void Waiting_reception(void)
{while(a==0)//等待数据发送完成{delay_ms(100);if(a==1)//接收到数据{if(USART_RX_STA&0x8000)//(串口接收用到了正点原子的例程){len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度r=len; type=0;for(t=0;t<len;t++)//拷贝数据,将字符转换为十进制数{receive_data[t]=USART_RX_BUF[t];data=(int)receive_data[t]-48;r=r-1;type=type+data*(pow(10,r));}USART_RX_STA=0;a=0;delay_ms(500);break;}}}
}
/*************************** 函数名:KeyStates* 描述 :监测按键状态* 输入 :无 * 输出 :无* 返回值:0/1
****************************/
u8 KeyStates()//按键状态
{static u8 i = 0;if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==0){delay();if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==0)while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==0);i = ~i;}return i;
}
/***************** 函数名:main* 描述 :主函数* 输入 :无 * 输出 :无
******************/
int main(void)
{NVIC_Configuration(); //中断初始化GPIO_Config(); //IO口初始化USART1_Config(); //串口初始化delay_init(); //延时函数初始化 GPIO_ResetBits(GPIOA, GPIO_Pin_11);//A11置零 A11——EAN+GPIO_ResetBits(GPIOA, GPIO_Pin_12);//A12置零 A12——DIR+while(1){delay_ms(100);Initial_state: printf("\r\n 请选择正反转,正转输入0,反转输入1 (以新行作为结束标志)\r\n"); Waiting_reception();state=type;//将接收到的数据给typeif(type==0)//电机正转{GPIO_SetBits(GPIOA, GPIO_Pin_12);//电机正转printf("\r\n 电机为正转模式,请输入旋转速度(rad/s),输入0返回初始模式 \r\n");/*********************************************此模块用于配置速度参数********************************************************/part1:Waiting_reception();speed =type;//将接收到的数据给speedif(speed==0)goto Initial_state;//如果是0则返回初始模式else{if(speed>=15){printf("\r\n 旋转速度>15rad/s,请重新选择旋转速度。\r\n");goto part1;}else printf("\r\n 电机旋转速度为%d rad/s,请输入旋转角度,输入0返回初始模式 \r\n",speed);}/*********************************************此模块用于配置角度参数********************************************************/ Waiting_reception();angle =type;//将接收到的数据给typefor(;;){if(angle>0)//接收到的数据不是0{TIM2_Master__TIM3_Slave_Configuration(speed,angle); // 配置TIM2和TIM3的重装值 ,改变电机转动速度和角度delay_ms(20000);//电机保护printf("\r\n 电机已旋转%d °,请输入下一次旋转角度,输入0返回初始模式; \r\n",angle);angle=0;Waiting_reception(); angle =type; }else{if(angle==0)goto Initial_state;//返回初始状态 else {printf("\r\n 角度错误,已返回初始模式 \r\n"); goto Initial_state;} }}}
/*********************************************反转模式********************************************************/ else{if(type==1){GPIO_ResetBits(GPIOA, GPIO_Pin_12);//电机反转printf("\r\n 电机为正转模式,请输入旋转速度(rad/s),输入0返回初始模式 \r\n");/*********************************************此模块用于配置速度参数********************************************************/part2: Waiting_reception();speed =type;//将接收到的数据给speedif(speed==0)goto Initial_state;//如果是0则返回初始模式else{if(speed>=15){printf("\r\n旋转速度>15rad/s,请重新选择旋转速度。\r\n");goto part2;}else printf("\r\n 电机旋转速度为%d rad/s,请输入旋转角度,输入0返回初始模式 \r\n",speed);}
/*********************************************此模块用于配置角度参数********************************************************/ Waiting_reception();angle =type;//将接收到的数据给typefor(;;){if(angle>0)//接收到的数据不是0{TIM2_Master__TIM3_Slave_Configuration(speed,angle); // 配置TIM2和TIM3的重装值 ,改变电机转动速度和角度delay_ms(20000);//电机保护printf("\r\n 电机已旋转%d °,请输入下一次旋转角度,输入0返回初始模式;\r\n",angle);angle=0;Waiting_reception(); angle =type; }else{if(angle==0)goto Initial_state;//返回初始状态 else {printf("\r\n 角度错误,已返回初始模式 \r\n"); goto Initial_state;} }}
/****************************************************************************************************************************/ }else{//if(a!=0)&(a!=1)type=NULL;printf("\r\n 输入无效 \r\n");goto Initial_state;//返回初始状态}}}
}
2.main.h程序
#ifndef _MAIN_H
#define _MAIN_H
#include <stm32f10x.h>
#include <usart1.h>
#include <misc.h>
#include <nvic.h>
#include <stdio.h>
#include "stm32f10x_tim.h"
#include "timer.h"
#endif
3.time.c程序
#include "timer.h"/*************************** 函数名:GPIO_Config* 描述 :无* 输入 :无 * 输出 :无* 调用 :主函数* 返回值:无
****************************/
void GPIO_Config(void)
{ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能IOARCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE); //使能TIM2,TIM3/* Timer2 Channel 1, PA0 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_11|GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //指定GPIO引脚可输出的最高频率为50MHZGPIO_Init(GPIOA, &GPIO_InitStructure); //GPIO_ResetBits(GPIOA, GPIO_Pin_1);//指定引脚输出低电平,此时灯全灭,方向GPIO_ResetBits(GPIOA, GPIO_Pin_2);//指定引脚输出低电平,此时灯全灭 使能GPIO_SetBits(GPIOA, GPIO_Pin_11);//指定引脚输出低电平,此时灯全灭,方向GPIO_SetBits(GPIOA, GPIO_Pin_12);//指定引脚输出低电平,此时灯全灭 使能GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //通用推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //指定GPIO引脚可输出的最高频率为50MHZGPIO_Init(GPIOA, &GPIO_InitStructure); //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //指定GPIO引脚可输出的最高频率为50MHZGPIO_Init(GPIOB, &GPIO_InitStructure); //GPIO_ResetBits(GPIOB, GPIO_Pin_12);//指定引脚输出低电平,此时灯全灭 使能//GPIO_ResetBits GPIO_SetBits
}//================================================================================/*************************** 函数名:TIM2_Master__TIM3_Slave_Configuration* 描述 :主从定时器配置* 输入 :电机转速speed,转角angle * 输出 :无* 调用 :主函数* 返回值:无
****************************/
void TIM2_Master__TIM3_Slave_Configuration(u32 PulseFrequency, u32 pulse)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; u16 nPDTemp ; u16 pulse_number;float p=PulseFrequency;TIM_Cmd(TIM2, DISABLE); nPDTemp = (11.25/p); //TIM2重装值是11.25时1s转一圈(电机32细分下)pulse_number = (16.7778*pulse);//TIM3重装值是16.7778时转1°(电机32细分下)// 时基配置:配置PWM输出定时器——TIM2 /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = nPDTemp; //定时周期为nPDTempTIM_TimeBaseStructure.TIM_Prescaler = 999; //预分频值1000,即f=72khzTIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分频因子,会影响滤波器采样频率,与本实验无影响TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //指定重复计数器值TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 输出配置:配置PWM输出定时器——TIM2 /* PWM1 Mode configuration: Channel1 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //TIM 脉冲宽度调制模式 1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高电平有效TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能输出TIM_OCInitStructure.TIM_Pulse = nPDTemp>>1;//50% //比较tim_ccr的值,输出脉冲发生跳变TIM_OC1Init(TIM2, &TIM_OCInitStructure); //初始化TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能 TIMx 在 CCR1 上的预装载寄存器TIM_ARRPreloadConfig(TIM2, ENABLE); //使能或者失能 TIMx 在 ARR 上的预装载寄存器// 时基配置:配置脉冲计数寄存器——TIM3 TIM_TimeBaseStructure.TIM_Period = pulse_number; //0x1900是360°;//改变给电机的脉冲个数 TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 输出配置:配置输出比较非主动模式定时器——TIM3// Output Compare Active Mode configuration: Channel1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive; //输出比较非主动模式,(匹配时设置输出引脚为无效 电平,当计数值为比较/捕获寄存器值相同时,强制输出为低电平) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0xFFFF; // 这里的配置值意义不大 TIM_OC1Init(TIM3, &TIM_OCInitStructure); // 配置TIM2为主定时器 // Select the Master Slave Mode TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //设置 TIM2 主/从模式并使能// Master Mode selection TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); //使用更新事件作为触发输出// 配置TIM3为从定时器 // Slave Mode selection: TIM3 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated); //选择 TIM3为从模式 TIM_SlaveMode_Gated-当触发信号(TRGI)为高电平时计数器时钟使能TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1); //选择 TIM3 输入触发源 TIM_TS_ITR1-TIM 内部触发 1TIM_ITRxExternalClockConfig(TIM3, TIM_TS_ITR1);//设置 TIM3 内部触发为外部时钟模式 TIM_TS_ITR1-TIM 内部触发 1TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); //使能TIM3 TIM 捕获/比较 1 中断源 TIM_Cmd(TIM2, ENABLE); TIM_Cmd(TIM3, ENABLE);
} /***************************************************** 函数名:Output_Pulse* 描述 :无* 输入 :无 * 输出 :无* 返回值:无
******************************************************/
void Output_Pulse(u16 Num)
{GPIO_ResetBits(GPIOA, GPIO_Pin_2);//指定引脚输出低电平,此时灯全灭 使能TIM3->CCR1 = Num; TIM3->CNT = 0; TIM_Cmd(TIM3, ENABLE); TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); TIM_Cmd(TIM2, ENABLE);
}/***************************************************** 函数名:angle_set* 描述 :无* 输入 :无 * 输出 :无* 返回值:无
******************************************************/
void angle_set(u8 dir,u8 angle)
{if(dir==0)GPIO_ResetBits(GPIOA, GPIO_Pin_1);//指定引脚输出低电平,此时灯全灭,方向elseGPIO_SetBits(GPIOA, GPIO_Pin_1);//指定引脚输出低电平,此时灯全灭,方向Output_Pulse(angle*6400);
}
4.time.h程序
#ifndef __TIMER_H
#define __TIMER_H
#include "main.h"
extern unsigned char Flag;
extern unsigned char TIM2_Pulse_TIM3_Counter_OK;
void GPIO_Config(void);
void TIM2_Master__TIM3_Slave_Configuration(u32 PulseFrequency,u32 pulse);
void Frequence_Setting(u32 PulseFrequency);
void Output_Pulse(u16 Num);
void angle_set(u8 dir,u8 angle);
#endif
5.usart1.c程序
#include <main.h>
#include <usart1.h>
#include <string.h>
#include <math.h>/******************************************************* 函数名:USART1_Config* 描述 :USART1 GPIO 配置,工作模式配置* 输入 :无* 输出 : 无* 调用 :外部调用
***************************************************** */
void USART1_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;/* config USART1 clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* USART1 GPIO config *//* Configure USART1 Tx (PA.09) as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);/* USART1 mode config */USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No ;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_Cmd(USART1, ENABLE);
}/******************************************************* 函数名:fputc* 描述 :重定向c库函数printf到USART1* 输入 :无* 输出 :无* 调用 :由printf调用
***************************************************** */
int fputc(int ch, FILE *f)
{/* 将Printf内容发往串口 */USART_SendData(USART1, (unsigned char) ch);while (!(USART1->SR & USART_FLAG_TXE));return (ch);
}/*-------------------------------------------------------------------------------*/
/******************************************************* 函数名:USART1_IRQHandler* 描述 :USART1中断服务函数* 输入 :无* 输出 :无* 调用 :中断调用
***************************************************** */
u8 Res;
extern int a;
u16 USART_RX_STA=0; //接收状态标记
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
void USART1_IRQHandler(void) //串口1中断服务程序{Res =USART_ReceiveData(USART1); //读取接收到的数据if((USART_RX_STA&0x8000)==0)//接收未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000; //接收完成了 }else //还没收到0X0D{ if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } }} a=1; }
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.OSIntExit();
#endif/******************* (C) COPYRIGHT 2012 WildFire Team *****END OF FILE************/
6.usart1.h程序
#ifndef __USART1_H
#define __USART1_H
#include <main.h>
#include <stdio.h>#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
int simple_atoi(char *source);
void USART1_Config(void);
#endif /* __USART1_H */
未完,待续…
——————————————————————————
源代码:
链接:https://pan.baidu.com/s/1PkmxkoeHfSfX06Gnj4Dr3A
提取码:eas7
——————————————————————————
2020.8.15更新
1.程序跑飞问题已解决,有时间了整理一下,再传上来
2.引脚问题
此次开发板是一个引脚比较少的板子,不同开发板可能拥有的引脚不一样,但是相同名字的芯片引脚功能是一样的,具体可以查一下f103芯片手册。
(1)KEY0和KEY1本实验中没用到,不用管,是外界的一个按键
(2)A 0 、 A3 、A11 、A 12 是普通的IO口
(3)A 3—3.3V这一接法是严重有问题的(好像知道为啥当时外接的按键老是冒火花了)
(4)PUL- DIR-不接引脚也可以(这里要打个问号,记得是这样,不敢百分百确定)
(5)串口引脚在USART1.C程序里可以查,两个,RX TX,这里需要大家对着自己的板子检查一下看有没有程序里的这两个引脚,没有换个口,并改一下程序
所以 可以把引脚修改为
A 0——PUL+
A12——DIR+
A11——EAN+
GND——EAN-
引脚功能
A0控制电机转速
A3控制按键
A11控制电机是否为锁死状态
A12控制电机正反转
f103手册
链接:https://pan.baidu.com/s/1VkVxkj2XKzbpsjQd_UibJw
提取码:kx14
利用STM32F103精确控制步进电机相关推荐
- 利用STM32F103最小系统做C2接口离线烧录器
前言 在做BLHeli_S电调的时候需要用下载器给EFM8BB21下载程序,这可能需要买C8051下载器.下载器下载也很麻烦.这就萌生出做一个C2接口的离线下载器的想法. 离线下载器想法: 1. 支持 ...
- 利用stm32控制步进电机 速度加速度控制
因为想申请 CSDN 博客认证需要一定的粉丝量,而我写了五年博客才 700 多粉丝,本文开启关注才可阅读全文,很抱歉影响您的阅读体验 利用stm32控制步进电机 尝试用42系步进电机做倒立摆,总结步进 ...
- 基于STM32F103的步进电机(ULN2003/28BYJ-48)角度和转速控制详细资料和驱动代码
基于STM32F103的步进电机(ULN2003/28BYJ-48)角度和转速控制详细资料和驱动代码 详细资料 1.技术参数 参数 值 参数 值 电压VDC 12 空载牵入频率 Hz ≥500 直流电 ...
- 【stm32开发日志】用stm32精确控制步进电机角度
前言:精确控制步进电机的原理见我之前写的一篇博文:https://blog.csdn.net/weixin_39589455/article/details/89409634 程序: 1.此处是pwm ...
- 基于STM32F103的步进电机S型曲线加减速算法与实现
步进电机是将电脉冲信号转变为角位移或线位移的开环控制电机,是现代数字程序控制系统中的主要执行元件,应用极为广泛.在非超载的情况下,电机的转速.停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的 ...
- python控制电机_利用树莓派控制步进电机——Python语言
步进电机的优点在于它能够被精确定位,正向或反向一次性转动"一步",并且也能够连续转动. #!/usr/bin/env python ######################## ...
- 利用STM32F103单片机输出SPWM波
最近需要用到单片机输出SPWM波功能,在网上找了好多资料,发现都不完整,有算法的没有代码,有代码的看不懂算法.于是只好自己摸索,现将方法整理如下. 关于什么是SPWM波,为什么要用SPWM波,网上的介 ...
- 利用STM32F103的DAC结合xtr111实现4-25mA输出的数据分析
通过数据和图片曲线,可以看出线性度还是不错的. 下面是输出电压,转换的电流,电流变化量的数据 V ma △ma 0 0.08 0 0.1 0.9 0.82 0.2 1.7 0.8 0.3 2.51 0 ...
- 【STM32】实战3.1—用STM32与TB6600驱动器驱动42步进电机(一)
目录 0 参考资料出处 1 实验预期效果 2 硬件学习 2.1 TB6600驱动器 2.1.1 通过拨码开关设定细分与电流 2.1.2 共阴共阳接线法 2.2 开关电源(AC转DC变压器)& ...
- stm32f103使用DM542控制42相步进电机的原理和可行性分析
步进电机是一种能够实现准确位置控制的电机,通常应用于需要高精度定位的场合,例如3D打印机.机器人和自动化系统等.而STM32F103是一种高性能.低功耗的微控制器,它拥有广泛的外设,适合用于控制各种电 ...
最新文章
- 现代密码学4.1--消息完整性
- 学习笔记:二叉搜索树的验证
- [转]字符编码,ansi, unicode,utf-8, utf-16
- 统计学的经典书籍指南 (转载自:http://blog.csdn.net/ysuncn/article/details/1943679)...
- “超人”助阵,IE静音很简单
- JAVA笔记20-容器之四Map接口、自动打包、泛型(重要)
- 硬件WAF的制作!linux系统制作硬件WAF,实现透明代理,具备断电、故障Bypass功能。...
- python 儿童教程_教孩子学编程PYTHON语言版PDF_Python教程
- 小程序中如何引用阿里图标
- NOIP2016 酱油记
- CYY文本批量助手2.0绿色版正式发布
- 微信公众平台开发-PHP版
- am5728通过DM框架配置GPIO管脚
- 产品经理考什么证书?考这个准没错
- kali linux查询自己的ip,Kali Linux常用服务配置教程获取IP地址
- 怎么修复linux受损文件,Linux文件数据损坏的快速修复办法-文件或目录损坏且无法读取...
- 解决github提交项目是出现10053的问题
- python机器人编程——四轴UARM机械臂的运动控制(逆解)原理及python实现(上)
- 河南省多校联盟二-F 线段树+矩阵
- Yolov5训练日记~如何用Yolov5训练识别自己想要的模型~
热门文章
- 8086汇编语言:8086CPU寄存器的相关介绍
- Java、JSP在线问卷调查系统的分析与实现
- 【演讲实录+PPT下载】一网打尽AI年度热点,2017中国人工智能大会资料曝光(持续更新)...
- python工具箱系列(三)
- html美化select样式,CSS美化select下拉框
- android当无线鼠标代码,如何将安卓手机变身为无线鼠标
- android九游sdk,九游单机SDK接入常见问题
- java wsimport 调用_java使用wsimport调用wcf接口
- 2017onsite比赛游记帖
- Linux使用.pem文件实现免密登录