利用STM32F103精确控制步进电机「建议收藏」

利用STM32F103精确控制步进电机「建议收藏」**利用STM32F103控制步进电机精确角度转动**欢迎使用Markdown编辑器你好!这是你第一次使用Markdown编辑器所展示的欢迎页。如果你想学习如何使用Markdown编辑器,可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,…

大家好,又见面了,我是你们的朋友全栈君。

利用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)f60

  • 转速单位: 转/ 分
  • 频率单位:赫兹
  • 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)7200060=112.5rad/ min,即1.875 rad/s.
    42步进电机结构图42步进电机结构图

三、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 = ( n P D T e m p 2 + 1 ) 72 M H z O C P o l a r i t y 2 + 1 T= \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 = 72000 5000 72 × 1 0 6 999 + 1 = 0.0002 s T= \frac{\frac{72000}{5000}}{ \frac{72\times 10^6}{999+1}}=0.0002s T=999+172×106500072000=0.0002s
  定时器共产生nPDTemp3+1=6400个脉冲,电机转过的角度为6400*1.8°=11520°,即电机转了32圈。
  转动速度
w = 1.8 ° / 360 ° T = 25 ( r a d / 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;//将接收到的数据给type
if(type==0)//电机正转
{ 

GPIO_SetBits(GPIOA, GPIO_Pin_12);//电机正转
printf("\r\n 电机为正转模式,请输入旋转速度(rad/s),输入0返回初始模式 \r\n");
/*********************************************此模块用于配置速度参数********************************************************/
part1:Waiting_reception();
speed =type;//将接收到的数据给speed
if(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;//将接收到的数据给type
for(;;)
{ 

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;//将接收到的数据给speed
if(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;//将接收到的数据给type
for(;;)
{ 

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); //使能IOA
RCC_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引脚可输出的最高频率为50MHZ
GPIO_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引脚可输出的最高频率为50MHZ
GPIO_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引脚可输出的最高频率为50MHZ
GPIO_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; //定时周期为nPDTemp
TIM_TimeBaseStructure.TIM_Prescaler = 999; //预分频值1000,即f=72khz
TIM_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 脉冲宽度调制模式 1
TIM_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 内部触发 1
TIM_ITRxExternalClockConfig(TIM3, TIM_TS_ITR1);//设置 TIM3 内部触发为外部时钟模式 TIM_TS_ITR1-TIM 内部触发 1
TIM_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);//指定引脚输出低电平,此时灯全灭,方向
else
GPIO_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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/138066.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 软件激活成功教程教程2[通俗易懂]

    软件激活成功教程教程2[通俗易懂]第四章–调试器及相关工具入门在写这章之前,我看了一下看雪以往的教程。本来想参考一下,可忽然发现,写这样的一章,是一件非常愚蠢的事情,因为我觉的关于这些工具的使用教程。看雪教程中已经写的够详细的了,我并不认为你会看不懂。所以我不想做浪费时间的人,本章就此搁浅。推荐看《CrackTutorial2001》,推荐看《看雪论坛精华一、二、三、四》,推荐看《加密与解密--软件保护技术及完全解决方案》,

  • 7000词汇这么背我比较可以接受,连续看20天足以[通俗易懂]

    7000词汇这么背我比较可以接受,连续看20天足以[通俗易懂]
    16天记住7000考研词汇(第一天)

    1.WithmyownearsIclearlyheardtheheartbeatofthenuclearbomb.
    我亲耳清楚地听到原子弹的心脏的跳动。
    2.Nextyearthebeardedbearwillbearadearbabyintherear.
    明年,长胡子的熊将在后方产一头可爱的小崽.
    3.EarlyIsearchedthr

  • Python抓取数据_python抓取游戏数据

    Python抓取数据_python抓取游戏数据前言本文整理自慕课网"《Python开发简单爬虫》",将会记录爬取百度百科“python”词条相关页面的整个过程。抓取策略确定目标:确定抓取哪个网站的哪些页面的哪部分数据

  • python怎么调用模块_切换模块的功能和特点

    python怎么调用模块_切换模块的功能和特点简介Python的PyYAML模块是Python的YAML解析器和生成器。安装简单安装pipinstallpyyaml从源码安装下载源码包PyYAML-3.13.tar.gz并解压,在命令行下切换到解压后的包目录内并执行如下命令:pythonsetup.pyinstall如果想使用比纯Python版本更快的LibYAML绑定,需要先下载并安装LibYAML,然后在安装…

  • 一个暑假额。。有一点进步。。要学的还有很多

    一个暑假都在安卓上了,本来眼高手低的觉得能学个差不多,没想到只学了个皮毛而已。到现在基本上了解了安卓的工作原理和一些常用api的调用,不过遇到瓶颈了,终于知道很多人劝的那句话,java基础很重要。现在体会到了,刚开始还能根据c++的理解大体写出小程序的细节,但是到后来,随着程序的增加,却是意识到需要系统的学习一下java,所以,前几天开始看李刚老师的疯狂java讲义,刚才因为出现了问题,一打开

  • 如何在Ubuntu终端下查看tensorflow版本

    如何在Ubuntu终端下查看tensorflow版本在Ubuntu终端下查看tensorflow版本,网上比较流行的方法是,在终端输入Pythonimporttensorflowastftf._version_但是显示没有tensorflow模块原因是没有激活tensorflow模块,这样就可以啦我的tensorflow安装路径是home/tensorflow,大家记得改为自己的安装路径

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号