标题:
stm32控制两相电机源程序
[打印本页]
作者:
ahld
时间:
2019-5-8 10:54
标题:
stm32控制两相电机源程序
这是我设计的stm32F103控制两相电机程序
测试好用
附件有keil工程文件
单片机源程序如下:
#include "Bsp.h"
#include "stm32f10x.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
#define DEBUG 1
char TestWord[USARTBUFLEN];
char Cmd_buf[USARTBUFLEN];
uint8_t Cmd_LockFlag = 0;
uint8_t ResetCmd_Flag = 0;
uint8_t Cmd_FinishFlag= 0;
#define ACKSTR "OK_\r\n"
#define NACKSTR "BADCMD_\r\n"
#define BUSYSTR "WAIT_\r\n"
char startchar[USARTBUFLEN];
const char CMD_LIST[8][PARASTRLEN]={"RESET","MOVE","STOP","POWER","SET","READ","ZERO"}; //允许的命令
const char HelpMsg[8][USARTBUFLEN]={{"Command List: MOVE STOP SET READ POWER ZERO;\r\n"},
{"MOVE: e.g. :FF MOVE VERTICAL/HORIZONT CW/ANCW xxx.xx(0-360,sOLUTION: 0.01);\r\n"},
{"STOP: e.g. :FF STOP VERTICAL/HORIZONT;\r\n"},
{"POWER: e.g. :FF POWER VERTICAL/HORIZONT ON/OFF;\r\n"},
{"SET: e.g. :FF SET VERTICAL/HORIZONT ;\r\n"},
{"READ: e.g. :FF READ VERTICAL/HORIZONT;\r\n"},
{"ZERO: e.g. :FF ZERO VERTICAL/HORIZONT;\r\n"},
{"RESET: e.g. :FF RESET;\r\n"}};
char CmdRespondStr[50];
char para_list[CMDPARANUM][PARASTRLEN]; //保存命令中的参数
SYSTEM_STA Sys_Sta;
void CMD_Analyse(const char *cmd,uint8_t cmdlen);
uint8_t str2float(const char *str,float *result);
u8 Flag=0; //指示输出角度是否到达360度或-360,如果到了,讲360置为0度
/****************************************************************************
* 名 称: main
* 功 能: 串口占用GPIO初始化
* 入口参数:
* 出口参数:
* 说 明:
* 调用方法:
* 修改日志:
****************************************************************************/
int main(void)
{
uint16_t temp[4],temp1=0,HVTemp1;
uint16_t data_tmp;
int32_t step_num = 0;
uint32_t devison_tmp,step_speed;
uint32_t sendbytes=0;
const char *usart_sendaddr;
float angle_tmp,speed_tmp,limit_tmp;
uint8_t error;
uint8_t tmp = 0;
uint8_t fault_try = 0;
STEPMOTOR_INDEX ver_hor;
MOTIONDIR cw_ncw;
uint8_t cycle_cnt,char_num;;
Cmd_LockFlag = 0;
Bsp_Init();
// AT24CXX_Write(0,HelpMsg[0],strlen(HelpMsg[0]));
usart_sendaddr = CmdRespondStr;
cycle_cnt = 0;
temp[0] = 0;
ResetCmd_Flag = 0;
#ifdef DEBUG
//打印识别信息
char_num = sprintf(startchar,"\r\n 134mm-Diameter Step-Motor Driver.\r\nCorp.AGGC,By LK,140\r\n");
UsartDMASend(startchar,char_num);
#endif
//上电首先检查振镜位置是否超出允许
/*
Delay_ms(5000);
if((RESET == GPIO_ReadInputDataBit(ANCW_LIMIT))|(RESET == GPIO_ReadInputDataBit(CW_LIMIT)))
{
Hor_Info.motion_sta = OutOfRange;
if(RESET == GPIO_ReadInputDataBit(ANCW_LIMIT))
{
Hor_Info.motion_dir = Motion_CW;
Hor_Info.dir_now = Hor_Info.dir_range_ancw;
}
else
{
Hor_Info.motion_dir = Motion_ANCW;
Hor_Info.dir_now = Hor_Info.dir_range_cw;
}
}
*/
while(1)
{
//程序运行指示灯
cycle_cnt++;
if(cycle_cnt > 1)
{
LEDToggle();
cycle_cnt =0;
}
//垂直电机位置超出允许范围,尝试反向转动3次,失败后,定义为振镜异常
/*
if(OutOfRange == Hor_Info.motion_sta)
{
Delay_ms(1000);
if((RESET == GPIO_ReadInputDataBit(ANCW_LIMIT))|(RESET == GPIO_ReadInputDataBit(CW_LIMIT)))
{
//
if(fault_try<3)
{
if(Stop== Hor_Info.motor_sta)
{
MOTOR_DISEN_HOR;
Hor_Info.motor_sta = Move;
Hor_Info.motor_fb = FB_Enable;
Move_Angles(Horizontal,Hor_Info.motion_dir,5); //尝试反向转5度,离开限位开关位置
MOTOR_START_HOR;
fault_try++;
}
}
else
{
Hor_Info.motion_sta = Fault;
MOTOR_EN_HOR;
}
}
}
else
fault_try = 0;
*/
//收到一条命令
if(1 == Cmd_FinishFlag)
{
Cmd_LockFlag =0; //串口命令解锁
Cmd_FinishFlag =0;
CMD_Analyse(Cmd_buf+1,30);
memset(Cmd_buf,0,USARTBUFLEN); //USARTBUFLEN=100 串口命令最大长度
//void *memset(void *s,int c,size_t n) 将已开辟内存空间S的首个n字节的值设置为C
sendbytes = sprintf(CmdRespondStr,NACKSTR); //sprintf字符串格式化命令,主要将格式化的数据写入字符串中
if(0 == strncmp(para_list[0],"MOVE",sizeof("MOVE"))) //电机运动命令,sizeof返回字节大小
{ //strncmp ( const char * str1, const char * str2, size_t n );str1,str2为需要比较的字符串,n为比较数量
//str1第一个字符减去str2第一个字符,若差值为0,则继续比较下一个字符
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
ver_hor = Vertical; //垂直
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
ver_hor = Horizontal; //水平
else
ver_hor = Unknow;
if(Unknow != ver_hor)
{
if(0 == str2float(para_list[2],&angle_tmp))
{
float end_angle=0;
end_angle= Motor_Info[ver_hor].angle_now+angle_tmp;
//当前位置不能超过设定范围
if((end_angle >= -1*Motor_Info[ver_hor].limit_angle)&&(end_angle <= Motor_Info[ver_hor].limit_angle))
{
if(angle_tmp >0)
{
cw_ncw = Motion_CW; //步进电机方向
}
else if(angle_tmp <0)
{
cw_ncw = Motion_ANCW;
angle_tmp *= -1;
}
else
cw_ncw = Hold;
}
else if(end_angle < -1*Motor_Info[ver_hor].limit_angle) //超过逆时针转动范围
{
cw_ncw = Motion_ANCW;
angle_tmp = Motor_Info[ver_hor].angle_now + Motor_Info[ver_hor].limit_angle;
}
else if(end_angle > Motor_Info[ver_hor].limit_angle) //超过顺时针转动范围
{
cw_ncw = Motion_CW;
angle_tmp = Motor_Info[ver_hor].limit_angle - Motor_Info[ver_hor].angle_now;
}
else
cw_ncw = Hold;
//电机停止状态下,才能允许转动
if((Hold != cw_ncw)&&(Stop == Motor_Info[ver_hor].motor_sta))
{
// Motor_Info[ver_hor].move_pulsenum =(uint32_t)(angle_tmp*CODER_NUM);
Move_Angles(ver_hor,cw_ncw,angle_tmp);
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
else
sendbytes = sprintf(CmdRespondStr,BUSYSTR);
// }
// else
// sendbytes = sprintf(CmdRespondStr,"AngleWrong_\r\n");
}
else sendbytes = sprintf(CmdRespondStr,NACKSTR);
}
}
else if(0 == strncmp(para_list[0],"CHECK",sizeof("CHECK"))) //查询当前电机状态(是否在转)
{
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
{
ver_hor = Vertical;
}
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
{
ver_hor = Horizontal;
}
else
ver_hor = Unknow;
if(Unknow != ver_hor)
{
if(Move == Motor_Info[ver_hor].motor_sta)
sendbytes = sprintf(CmdRespondStr,"MOVE_\r\n");
else
sendbytes = sprintf(CmdRespondStr,"HOLD_\r\n");
}
}
else if(0 == strncmp(para_list[0],"STATUS",sizeof("STATUS"))) //查询当前电机状态(是否在转)
{
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
{
ver_hor = Vertical;
}
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
{
ver_hor = Horizontal;
}
else
ver_hor = Unknow;
if(Unknow != ver_hor)
{
if(Stepslost == Motor_Info[ver_hor].motion_sta)
sendbytes = sprintf(CmdRespondStr,"STEPSLOST_\r\n");
else if(OutOfRange == Motor_Info[ver_hor].motion_sta)
sendbytes = sprintf(CmdRespondStr,"OVERRANGE_\r\n");
else if(Zero == Motor_Info[ver_hor].motion_sta)
sendbytes = sprintf(CmdRespondStr,"ZERO_\r\n");
else if(Fault == Motor_Info[ver_hor].motion_sta)
sendbytes = sprintf(CmdRespondStr,"FAULT_\r\n");
else
sendbytes = sprintf(CmdRespondStr,"NORMAL_\r\n");
}
}
else if(0 == strncmp(para_list[0],"STOP",sizeof("STOP"))) //运动停止命令
{
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
ver_hor = Vertical;
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
ver_hor = Horizontal;
else
ver_hor = Unknow;
if(Unknow != ver_hor)
{
if(Vertical == ver_hor)
{
Ver_Info.motor_sta = Stop;
Ver_Info.motor_fb = FB_Disable;
MOTOR_STOP_VER;
}
else
{
Hor_Info.motor_sta = Stop;
Hor_Info.motor_fb = FB_Disable;
MOTOR_STOP_HOR;
}
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
}
else if(0 == strncmp(para_list[0],"SET",sizeof("SET"))) //参数设置命令
{
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
ver_hor = Vertical;
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
ver_hor = Horizontal;
else
ver_hor = Unknow;
//电机停止时,允许进行参数设定
if(Stop == Motor_Info[ver_hor].motor_sta)
{
if(Unknow != ver_hor)
{
if(0 == strncmp(para_list[2],"DEVISION",sizeof("DEVISION"))) //设置细分比例
{
devison_tmp = atoi(para_list[3]);
if((devide_1 == devison_tmp)|(devide_2 == devison_tmp)|(devide_8 == devison_tmp)|(devide_16 == devison_tmp))
{
if(Vertical == ver_hor)
{
Ver_Info.subdevision = (DEVISIONVALUE)devison_tmp;
Ver_Info.step_resolution= MOTOR_RESOLUTION/(RATIO_GEAR*devison_tmp);
Ver_Info.step_speed = 360.0f*Ver_Info.speed/(60.0f*Ver_Info.step_resolution);
SPEEDSET_VER(1000000/Ver_Info.step_speed);
Ver_Info.dir_range_cw = (int32_t)RATIO_GEAR*Ver_Info.subdevision*180/MOTOR_RESOLUTION; //顺时针电机方位角范围
Ver_Info.dir_range_ancw = -1*(int32_t)RATIO_GEAR*Ver_Info.subdevision*180/MOTOR_RESOLUTION; //逆时针电机方位角范围
//更新EEPROM中保存的参数
UPDATE_DEVISIONH_VER;
UPDATE_STEPRE_VER;
UPDATE_SPEED_VER;
UPDATE_DIRRANGE_VER;
}
else if(Horizontal == ver_hor)
{
Hor_Info.subdevision =(DEVISIONVALUE)devison_tmp;
Hor_Info.step_resolution= MOTOR_RESOLUTION/(RATIO_GEAR*devison_tmp);
Hor_Info.step_speed = 360.0f*Hor_Info.speed/(60.0f*Hor_Info.step_resolution);
SPEEDSET_HOR(1000000/Hor_Info.step_speed);
Hor_Info.dir_range_cw = (int32_t)RATIO_GEAR*Hor_Info.subdevision*360/MOTOR_RESOLUTION; //顺时针电机方位角范围
Hor_Info.dir_range_ancw = -1*(int32_t)RATIO_GEAR*Hor_Info.subdevision*360/MOTOR_RESOLUTION; //逆时针电机方位角范围
AT24CXX_Write(HORINFO_ADDR,(const uint8_t *)&Hor_Info,sizeof(MOTORINFO));
//更新EEPROM中保存的参数
UPDATE_DEVISIONH_HOR;
UPDATE_STEPRE_HOR;
UPDATE_SPEED_HOR;
UPDATE_DIRRANGE_HOR;
}
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
}
else if(0 == strncmp(para_list[2],"LOCATION",sizeof("LOCATION"))) //设置当前位置对应角度,手动归零时使用该命令
{
if(0 == str2float(para_list[3],&angle_tmp))
{
if((angle_tmp >= -185)&&(angle_tmp <= 185))
{
if(Vertical == ver_hor)
{
Ver_Info.angle_now = angle_tmp;
Ver_Info.dir_now = angle_tmp/360.0f*Ver_Info.dir_range_cw*2;
//更新EEPROM中保存的参数
UPDATE_ANGEL_VER;
UPDATE_DIRNOW_VER;
}
else if(Horizontal == ver_hor)
{
Hor_Info.angle_now = angle_tmp;
Hor_Info.dir_now = angle_tmp/360.0f*Hor_Info.dir_range_cw*2;
//更新EEPROM中保存的参数
UPDATE_ANGEL_HOR;
UPDATE_DIRNOW_HOR;
}
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
}
}
else if(0 == strncmp(para_list[2],"SPEED",sizeof("SPEED"))) //设置转动速度
{
speed_tmp = atof(para_list[3]);
if((speed_tmp > 0)&&(speed_tmp <= 2000)) //分钟转速小于2000r/min
{
if(Vertical == ver_hor)
{
Ver_Info.speed = speed_tmp;
Ver_Info.step_speed = 360.0f*Ver_Info.speed/(60.0f*Ver_Info.step_resolution);
SPEEDSET_VER(1000000/Ver_Info.step_speed);
//更新EEPROM中保存的参数
UPDATE_SPEED_VER;
UPDATE_SPEEDSTEPS_VER;
// AT24CXX_Write(VERINFO_ADDR,(const uint8_t *)&Ver_Info,sizeof(MOTORINFO));
}
else if(Horizontal == ver_hor)
{
Hor_Info.speed = speed_tmp;
Hor_Info.step_speed = 360.0f*Hor_Info.speed/(60.0f*Hor_Info.step_resolution);
SPEEDSET_HOR(1000000/Hor_Info.step_speed);
// AT24CXX_Write(HORINFO_ADDR,(const uint8_t *)&Hor_Info,sizeof(MOTORINFO));
//更新EEPROM中保存的参数
UPDATE_SPEED_HOR;
UPDATE_SPEEDSTEPS_HOR;
}
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
}
else if(0 == strncmp(para_list[2],"LIMIT",sizeof("LIMIT"))) //设置转动范围
{
if(0 == str2float(para_list[3],&limit_tmp))
{
if((limit_tmp > 0)&&(limit_tmp <= 361))
{
Motor_Info[ver_hor].limit_angle = limit_tmp;
if(Vertical == ver_hor)
UPDATE_LIMITANGEL_VER;
else
UPDATE_LIMITANGEL_HOR;
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
}
}
}
}
else
sendbytes = sprintf(CmdRespondStr,BUSYSTR);
}
else if(0 == strncmp(para_list[0],"READ",sizeof("READ"))) //读取细分参数命令
{
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
ver_hor = Vertical;
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
ver_hor = Horizontal;
else
ver_hor = Unknow;
if(Unknow != ver_hor)
{
if(0 == strncmp(para_list[2],"DEVISION",sizeof("DEVISION"))) //读取细分比例
{
if(Vertical == ver_hor)
sendbytes = sprintf(CmdRespondStr,"Vertical_Devision_%d_\r\n",Ver_Info.subdevision);
else if(Horizontal == ver_hor)
sendbytes = sprintf(CmdRespondStr,"Horizontal_Devision_%d_\r\n",Hor_Info.subdevision);
}
else if(0 == strncmp(para_list[2],"LOCATION",sizeof("LOCATION"))) //读取当前位置对应角度
{
if(Vertical == ver_hor)
sendbytes = sprintf(CmdRespondStr,"%.2f_\r\n",Ver_Info.angle_now);
else if(Horizontal == ver_hor)
sendbytes = sprintf(CmdRespondStr,"%.2f_\r\n",Hor_Info.angle_now);
}
else if(0 == strncmp(para_list[2],"SPEED",sizeof("SPEED"))) //读取当前位置对应步进速度
{
if(Vertical == ver_hor)
sendbytes = sprintf(CmdRespondStr,"%.2d_\r\n",Ver_Info.step_speed);
else if(Horizontal == ver_hor)
sendbytes = sprintf(CmdRespondStr,"%.2d_\r\n",Hor_Info.step_speed);
}
else if(0 == strncmp(para_list[2],"LIMIT",sizeof("LIMIT"))) //设置转动范围
{
if(Vertical == ver_hor)
sendbytes = sprintf(CmdRespondStr,"%.1f_\r\n",Ver_Info.limit_angle);
else if(Horizontal == ver_hor)
sendbytes = sprintf(CmdRespondStr,"%.1f_\r\n",Hor_Info.limit_angle);
}
}
}
else if(0 == strncmp(para_list[0],"ZERO",sizeof("ZERO"))) //角度归零,待完善
{
if(0 == strncmp(para_list[1],"VERTICAL",sizeof("VERTICAL")))
ver_hor = Vertical;
else if(0 == strncmp(para_list[1],"HORIZONT",sizeof("HORIZONT")))
ver_hor = Horizontal;
else
ver_hor = Unknow;
if(Unknow != ver_hor)
{
ZeroMotor(ver_hor);
sendbytes = sprintf(CmdRespondStr,ACKSTR);
}
}
else if(0 == strncmp(para_list[0],"HELP",sizeof("HELP"))) //命令使用信息查询
{
usart_sendaddr =HelpMsg[0];
sendbytes =strlen(HelpMsg[0]);
}
else if(0 == strncmp(para_list[0],"RESET",sizeof("RESET"))) //系统复位命令
{
//复位前,停止电机转动
MOTOR_STOP_HOR;
MOTOR_STOP_VER;
Sys_Soft_Reset();
}
else
sendbytes = sprintf(CmdRespondStr,NACKSTR);
for(tmp=0;tmp<CMDPARANUM;tmp++)
memset(para_list[tmp],0,PARASTRLEN);
}
//DMA空闲时,将数据发送出去
if((0 == DMA_GetCurrDataCounter(PC_DMA_CHANNEL))&&(sendbytes > 0))
{
UsartDMASend(usart_sendaddr,sendbytes);
usart_sendaddr = CmdRespondStr;
sendbytes =0;
}
//将方位更新到角度,并判断是否超过设定范围
Ver_Info.angle_now = (float)Ver_Info.dir_now*Hor_Info.step_resolution;
Hor_Info.angle_now = (float)Hor_Info.dir_now*Hor_Info.step_resolution; //当前的角度为实际脉冲数计算得到,angle_now=360*dir_now/(2*200*140) (细分比率*200*次轮比)
UPDATE_ANGEL_HOR;
UPDATE_DIRNOW_HOR;
UPDATE_ANGEL_VER;
UPDATE_DIRNOW_VER;
WG_Feed();
}
}
/****************************************************************************
* 名 称: str2float()
* 功 能:收到的角度是否合法
* 入口参数:
* 出口参数:
* 说 明:
* 调用方法:
* 修改日志:
****************************************************************************/
uint8_t str2float(const char *str,float *result)
{
uint8_t charcnt;
volatile uint8_t isok=1;
uint8_t paracnt =0;
uint8_t paracharcnt =0;
uint8_t point_flag =0;
uint8_t num_flag =0;
uint8_t sym_flag =0;
uint8_t sym_loc =0;
for(charcnt=0;charcnt<PARASTRLEN;charcnt++)
{
if(('-' == *(str+charcnt))|('-' == *(str+charcnt)))
{
sym_flag = charcnt+1;
if(sym_flag>1)
break; //符号位超过一个
}
……………………
…………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
StepMotor_LV4(134口径振镜源代码).7z
(180.66 KB, 下载次数: 32)
2019-5-8 20:51 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
ahld
时间:
2019-5-8 13:35
不错不错哟
作者:
admin
时间:
2019-5-8 20:51
本帖需要重新编辑补全电路原理图,源码,详细说明与图片即可获得100+黑币(帖子下方有编辑按钮)
作者:
Chenw_Fly
时间:
2020-12-31 10:06
目前在了解这个,感谢楼主的分享
作者:
mouse_ox
时间:
2021-1-1 20:17
不错不错,感谢楼主的分享!
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1