『壹』 怎麼用stm32這樣的單片機控制4G模塊
如果是AT命令方式,比較簡單。通過串口發送AT命令就能控制。如果想撥號上網有點麻煩,因為我過的4G,需要SDK來和模塊通信。而SDK只提供linux平台的驅動。
或者有的4G模塊,PCIE直接支持ACM驅動,但是這也得LINUX支持。單純的STM32想支持撥號方式的上網,有些困難。
『貳』 用stm32單片機 如何用按鍵控制繼電器的吸合
你說的問題很簡單:就是讓單片機的不斷檢測某一個輸入埠,這個埠的電位由一個按鍵控制,如果這個按鍵閉合,就將某一個輸出埠置高電平,通過介面電路控制繼電器線圈通電,即吸合。反之,當檢測到按鍵釋放,就將某一個輸出埠置低電平,通過介面電路控制繼電器線圈斷電,即釋放。
根據這個思想你就自己編一個小程序就可以了。
『叄』 用stm32單片機怎麼控制步進電機的正轉,反轉。剛學單片機。好多疑問啊。
剛學單片機就用STM32?好牛叉的樣子。
控制方法很簡單,
比如五線四相步進電機
四拍控制,輪流給每一相一次高電平(其他相低電平),A--延時--B--延時----C---延時--D--延時----A----延時--B這樣循環,但是頻率不能太大,一般步進電機轉速在1200轉/s以內,反轉倒過來給電平就行了,D--C--B---A
詳細請網路搜步進電機
『肆』 STM32單片機怎麼產生脈沖信號控制步進電動機
STM32單片機怎麼產生脈沖信號控制步進電動機:
#include "stepmotor.h"
#include
u32 PUL_CNT; // TIM3脈沖計數
vu32 step_done;
vu32 run_state;
#define run_state_stop 0
#define run_state_acc 1
#define run_state_run 2
#define run_state_dec 3
void STEPMOTOR_CTRL_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //GPIO時鍾使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //定時器3時鍾使能
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //定時器2時鍾使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //PA7為TIM3通道2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推免輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO口響應速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //PA6為DIR控制輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推免輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO口響應速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
//TIM3_Configuration
TIM_TimeBaseStructure.TIM_Period = 23999; //自動重裝載寄存器
TIM_TimeBaseStructure.TIM_Prescaler = 2; //預分頻器,t=(23999+1)*(2+1)/72M
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器向上計數模式
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時鍾分頻因子
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0; //每次溢出都產生事件更新
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //寫TIM3各寄存器參數
TIM_ClearFlag(TIM3,TIM_FLAG_Update); //中斷標志位清零
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允許捕獲/比較3中斷
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2 TIM3_CCMR1[14:12]=111 在向上計數時,一旦TIMx_CNT
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //輸入/捕獲2輸出允許
TIM_OCInitStructure.TIM_Pulse = 40; //確定占空比,這個值決定了有效電平的時間。
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性,低電平有效
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //配置定時器輸出模式,比較參數等
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的預裝載寄存器
//TIM2_Configuration
TIM_DeInit(TIM2); //TIM2重新配置為預設值,默認狀態
TIM_TimeBaseStructure.TIM_Period = 359; //自動重裝載寄存器
TIM_TimeBaseStructure.TIM_Prescaler = 199; //時鍾預分頻器
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器向上計數模式
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時鍾分頻因子
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //配置TIM2寄存器各參數
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //中斷標志位清零
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //允許捕獲/比較2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ; //選擇定時器TIM3
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //選擇搶先式優先順序(與中斷嵌套級別有關)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //選擇子優先順序(同搶先式優先順序的響應順序)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //選擇使能中斷源
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn ; //選擇定時器TIM2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //選擇搶先式優先順序(與中斷嵌套級別有關)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //選擇子優先順序(同搶先式優先順序的響應順序)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //選擇使能中斷源
NVIC_Init(&NVIC_InitStructure);
}
void TIM3_Configuration(u32 period)
{
TIM3->ARR = period-1;
TIM3->CCR2 = period >> 2;
//TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//TIM_OCInitTypeDef TIM_OCInitStructure;
//TIM_TimeBaseStructure.TIM_Period = period-1; //自動重裝載寄存器
//TIM_TimeBaseStructure.TIM_Prescaler = 29; //預分頻器,f=72M/[(period+1)*(29+1)], ft = 2400000
//TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器向上計數模式
//TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時鍾分頻因子
//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0; //每次溢出都產生事件更新
//TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //寫TIM3各寄存器參數
//TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2 TIM3_CCMR1[14:12]=111 在向上計數時,一旦TIMx_CNT
//TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //輸入/捕獲2輸出允許
//TIM_OCInitStructure.TIM_Pulse = period >> 2; //確定占空比,25%
//TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性,低電平有效
//TIM_OC2Init(TIM3, &TIM_OCInitStructure); //配置定時器輸出模式,比較參數等
}
//void MOTOR_RUN(u32 acc, u32 dec, u32 topspeed, u32 dis)
//步進電機運行參數
//acc -- 加速度,單位: round/min/s
//dec -- 減速度,單位: round/min/s
//topspeed -- 最高速度,單位: round/min
//dis -- 總角位移,單位: round/10000
void MOTOR_RUN(u32 acc, u32 dec, u32 topspeed, u32 dis)
{
u32 t_acc,t_dec,step_all,step_acc,step_dec,step_run;
u32 i,tim_cnt,tim_rest,tim_cnt_temp;
step_all = (float)dis * (N_MOTOR * 0.0001);
t_acc = topspeed * 1000 / acc; //unit: ms
t_dec = topspeed * 1000 / dec; //unit: ms
if(topspeed * (t_acc + t_dec) / 12 > dis) //達不到最高速度 // topspeed/60/1000 * (t_acc + t_dec) / 2 > dis / 10000
{
topspeed = sqrt(dis * acc * dec * 12 / (acc + dec) / 1000);
t_acc = topspeed * 1000 / acc; //unit: ms
t_dec = topspeed * 1000 / dec; //unit: ms
}
step_acc = N_MOTOR * ((float)topspeed*topspeed/(acc*120));
step_dec = N_MOTOR * ((float)topspeed*topspeed/(dec*120));
if(step_all > step_acc + step_dec)
step_run = step_all - step_acc - step_dec;
else
step_run = 0;
//tim_cnt = 5.2363 * ft / (sqrt(acc*N_MOTOR/2)); //(ft * sqrt(60)*0.676) / sqrt(acc*N_MOTOR/2);
tim_cnt = 7.7460 * ft / (sqrt(acc*N_MOTOR/2));
tim_rest = 0;
i = 0;
TIM3_Configuration(tim_cnt);
run_state = run_state_acc;
TIM_Cmd(TIM3,ENABLE);
step_done = 0;
while(step_done==0);
while(i
{
i++;
//tim_cnt_temp = tim_cnt;
//tim_cnt = tim_cnt - (2*tim_cnt+tim_rest) / (4*i+1);
//tim_rest = (2*tim_cnt_temp+tim_rest) % (4*i+1);
tim_cnt_temp = tim_cnt / ( sqrt((float)(i+1)) + sqrt((float)(i)) );
TIM3_Configuration(tim_cnt_temp);
step_done = 0;
while(step_done==0);
}
if(step_run > 0)
{
run_state = run_state_run;
tim_cnt = ft * 60 / (N_MOTOR*topspeed);
i = 0;
TIM3_Configuration(tim_cnt);
while(i
{
step_done = 0;
while(step_done==0);
i++;
}
}
run_state = run_state_dec;
tim_rest = 0;
i=0;
tim_cnt = tim_cnt + (2*tim_cnt+tim_rest) / (4*(step_dec-i)-1);
while(i
{
TIM3_Configuration(tim_cnt);
step_done = 0;
while(step_done==0);
i++;
tim_cnt_temp = tim_cnt;
tim_cnt = tim_cnt + (2*tim_cnt+tim_rest) / (4*(step_dec-i)-1);
tim_rest = (2*tim_cnt_temp+tim_rest) % (4*(step_dec-i)-1);
}
run_state = run_state_stop;
TIM_Cmd(TIM3,DISABLE);
}
void TIM2_IRQHandler(void)
{
}
void TIM3_IRQHandler(void)
{
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
step_done = 1;
//PUL_CNT++;
}
文件:stepmotor.h 聲明步進電機控制頭文件
#define N_MOTOR 10000 //步進電機細分
#define ft 24000000
void STEPMOTOR_CTRL_INIT(void);
void MOTOR_RUN(u32 acc, u32 dec, u32 topspeed, u32 dis);
文件:main.c 主函數,設置加速度,減速度,最大速度和步數的參數值
#include "main.h"
#define LED_SET() GPIO_SetBits(GPIOB,GPIO_Pin_8)
#define LED_RST() GPIO_ResetBits(GPIOB,GPIO_Pin_8)
#define SET_DIR_CW() GPIO_SetBits(GPIOA,GPIO_Pin_6)
#define SET_DIR_CCW() GPIO_ResetBits(GPIOA,GPIO_Pin_6)
void NVIC_Configuration(void);
void LED_init(void);
void soft_delayms(u16 t);
int main(void)
{
SystemInit();
STEPMOTOR_CTRL_INIT();
soft_delayms(1000);
while(1)
{
SET_DIR_CW();
MOTOR_RUN(600,600,1000,500000);
soft_delayms(1000);
SET_DIR_CCW();
MOTOR_RUN(600,600,1000,500000);
soft_delayms(1000);
}
return 0;
}
void NVIC_Configuration(void)
{
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0000); //將中斷矢量放到Flash的0地址
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //設置優先順序配置的模式,詳情請閱讀原材料中的文章
}
void LED_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void soft_delayms(u16 t)
{
u16 tt;
while(t--)
{
tt = 10000;
while(tt--);
}
}
#ifndef _MAIN_H
#define _MAIN_H
#include "stm32f10x.h"
#include "stepmotor.h"
#endif
『伍』 stm32單片機能寫復雜控制演算法么
1.PID原理
1.1 P I D三個參數簡單理解
1.2 P I D
1.3 PI PD PID適用系統
2.串級PID原理
3.PID代碼
3.1 單級PID
3.1.1 初始化PID結構體
3.1.2 單級PID計算
3.1.3PID初始化
3.1.4 清空PID
3.2 串級PID
3.2.1 初始化串級PID結構體
3.2.2 串級PID計算
4.PID的使用
4.1 定義PID結構體並初始化
4.2 定義電機速度函數
4.3 在檢測霍爾碼盤時發送速度給電機
4.4 實驗效果
1.PID原理
PID是什麼,P,I,D的分別功能
你和PID調參大神之間,就差這篇文章!
1.1 P I D三個參數簡單理解
P(比例): 簡單來說,P就是涼了加熱水,熱了加涼水。比目標值小,我就增加一點,比目標值大,我就減小一點。(現在)
P可能出現的問題: 1.P太小,達到目標值需要花費很長的時間,而且會有穩態誤差。2.P太大,達到目標值時可能會一直震盪。
I(積分): 將一段時間內的誤差累積起來加到輸出上,可以消除歷史誤差對當前實際曲線的影響,提高系統的穩定性。 (過去)
I可能出現的問題: 1.I太小,可以消除穩態誤差,但太慢了,對於某些需要很快響應的系統,顯然不能滿足要求。2.I太大,累計誤差佔比過大,就會出現抖動現象,難以收斂。
D(微分): 減小最大超調量。(下圖中③就是最大超調量。) 可以有效減小震動的幅度。讓曲線收斂更快 (未來)
D可能出現的問題: 1.D太小,作用小,時間長。2.D太大,為了減小超調量,補償的過多,導致震盪很久。
在這里插入圖片描述
1.2 P I D
先調P,逐漸增加P直到系統出現震盪,將當前值乘0.7就是較為合適的值。
再調I,將穩態誤差逐漸降低。
後調D,將最大超調量降到最低。
1.3 PI PD PID適用系統
PI:響應速度要求不那麼高的系統。
PD:大慣性系統。超調量太大。
PID:都可以。
網上將PID原理太多太多了,我的理解也都是參見上面的內容。認真看肯定有收獲。
2.串級PID原理
【串級PID】淺談串級PID作用及意義——快速理解串級PID結構優勢
這里個人理解就是,單機PID就是穩定速度。而需要帶位置和角度的就要用串級PID了。常用於平衡車,板球系統等。
而轉速閉環稱為串級PID的內環,位置 (角度) 閉環稱為串級PID的外環。其實也很好理解,位移是速度的積分,只有速度慢慢穩定,位置才能確定。
3.PID代碼
3.1 單級PID
3.1.1 初始化PID結構體
typedef struct _PID
{
float kp,ki,kd;
float error,lastError;//誤差、上次誤差
float integral,maxIntegral;//積分、積分限幅
float output,maxOutput;//輸出、輸出限幅
}PID;
1
2
3
4
5
6
7
1
2
3
4
5
6
7
3.1.2 單級PID計算
#define LIMIT(x,min,max) (x)=(((x)<=(min))?(min):(((x)>=(max))?(max):(x)))
//單級pid計算
void PID_SingleCalc(PID *pid,float reference,float feedback)
{
//更新數據
pid->lastError=pid->error;
pid->error=reference-feedback;
//計算微分
pid->output=(pid->error-pid->lastError)*pid->kd;
//計算比例
pid->output+=pid->error*pid->kp;
//計算積分
pid->integral+=pid->error*pid->ki;
LIMIT(pid->integral,-pid->maxIntegral,pid->maxIntegral);//積分限幅
pid->output+=pid->integral;
//輸出限幅
LIMIT(pid->output,-pid->maxOutput,pid->maxOutput);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.1.3PID初始化
void PID_Init(PID *pid,float p,float i,float d,float maxI,float maxOut)
{
pid->kp=p;
pid->ki=i;
pid->kd=d;
pid->maxIntegral=maxI;
pid->maxOutput=maxOut;
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
3.1.4 清空PID
//清空一個pid的歷史數據
void PID_Clear(PID *pid)
{
pid->error=0;
pid->lastError=0;
pid->integral=0;
pid->output=0;
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
3.2 串級PID
3.2.1 初始化串級PID結構體
typedef struct _CascadePID
{
PID inner;//內環
PID outer;//外環
float output;//串級輸出,等於inner.output
}CascadePID;
1
2
3
4
5
6
1
2
3
4
5
6
3.2.2 串級PID計算
//串級pid計算
void PID_CascadeCalc(CascadePID *pid,float angleRef,float angleFdb,float speedFdb)
{
PID_SingleCalc(&pid->outer,angleRef,angleFdb);//計算外環(角度環)
PID_SingleCalc(&pid->inner,pid->outer.output,speedFdb);//計算內環(速度環)
pid->output=pid->inner.output;
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7
4.PID的使用
STM32應用(九)編碼器及其測速原理、L298N電機驅動控制編碼器電機
在這篇博客的配置下,只需要修改部分代碼。以單級PID為例子。
4.1 定義PID結構體並初始化
PID pid;
void Motor_Init(void)
{
PID_Init(&pid,10,0,0,1000,1000);
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //開啟編碼器定時器
__HAL_TIM_ENABLE_IT(&htim1,TIM_IT_UPDATE); //開啟編碼器定時器更新中斷,防溢出處理
HAL_TIM_Base_Start_IT(&htim6); //開啟10ms定時器中斷
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //開啟PWM
__HAL_TIM_SET_COUNTER(&htim1, 10000); //編碼器定時器初始值設定為10000
motor.loopNum = 0; //防溢出
}
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
4.2 定義電機速度函數
void Motor_Send()
{
float output = 0;
PID_SingleCalc(&pid, motor.targetSpeed, motor.speed);
output = pid.output;
if(output > 0) //正轉
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)output);
IN1(1);
IN2(0);
}
else //反轉
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)(-output));
IN1(0);
IN2(1);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4.3 在檢測霍爾碼盤時發送速度給電機
if(htim->Instance==htim6.Instance) //10ms中斷
{
int16_t pluse = COUNTERNUM - RELOADVALUE/2;
motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2;
motor.speed = (float)(motor.totalAngle - motor.lastAngle)/(4*13*RR)*6000; //進行速度計算,根據前文所說的,4倍頻,編碼器13位,減速比30,再乘以6000即為每分鍾輸出軸多少轉
motor.lastAngle = motor.totalAngle; //更新轉過的圈數
Motor_Send();//發送速度
}
『陸』 STM32怎麼實現單片機控制LED燈常亮10S後熄滅
首先實現LED燈的點亮和熄滅,控制連接LED燈的管腳輸出高低電平就可以實現。如果電流比較大可以增加三極體驅動電路。10秒定時可以用定時器實現,設置一個1秒的定時器。上電點亮LED燈,並開始計時,10秒時間到熄滅LED就可以了。