国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

基于stm32的減速直流電機PID算法控制

這篇具有很好參考價值的文章主要介紹了基于stm32的減速直流電機PID算法控制。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

本例程采用了HAL庫進行項目開發(fā)(主要使用軟件CubexMX和keil5),文章末尾會有代碼開源,歡迎各位對文章進行指正和探討。

基于PID的減速電機控制

一、 硬件模塊與原理圖? ?

1、硬件組成? ?

????????硬件組成:stm32f103c8t6最小系統(tǒng)板;0.96寸LED12864(I2C通訊模式);智能小車12v移動電源;25GA370直流減速電機(帶霍爾編碼器);JDY-31藍牙模塊;L298N電機驅(qū)動模塊;杜邦線若干;1個面包板;

圖片如下:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

2、模塊分析

? ? ? ? 1、L298N電機驅(qū)動模塊

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????1.模塊可驅(qū)動兩路直流電機,輸出A和B各接一直流電機即可;

????????2.若使用12V供電,將12V供電端口及GND接上電源正負(fù)即可,同時5V供電端可以作為最小系統(tǒng)板的輸入電源;

????????3.若不需要使用PWM調(diào)速,只需要控制電機正反轉(zhuǎn),則邏輯A與B跳線帽插上即可,相當(dāng)于始終使能;

????????4.若需要使用PWM調(diào)速,需將跳線帽拔起,將使能端接上單片機IO口。(定時器IO口,PWM輸出模式);

????????5.邏輯輸入四個端口IN1、IN2、IN3、IN4接單片機四個IO口,每兩個端口控制的一路電機。

????????溫馨提示: 特別不建議新手或者資金有限的情況下,使用電機驅(qū)動模塊直連成品開發(fā)板,很容易燒壞。

????????原因:(1) 由于電機的特性,電機在堵轉(zhuǎn)或者高負(fù)載下,電流會增大,可能會影響到單片機。(2)新手玩單片機可能出現(xiàn)短路等情況,很容易板子冒煙;

L298N的轉(zhuǎn)動邏輯圖:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

? ? ? ? 2、0.96寸OLED(I2C通訊)

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????(1)目前市面主要分為OLED與LCD這2種屏幕;

????????(2)OLED自發(fā)光特性,LCD都要背光,而OLED不需要,因為它是自發(fā)光。這樣同樣的顯示,OLED效果要來得好一些;

????????(3)多種接口方式:6800,8080兩種并行接口方式,4線的穿行SPI接口,IIC接口方式(2線);

????????(4)不要接過高電壓,3.3V就可以正常工作了;

????????(5)OLED不足之處是做大之后成本較高。

????????本實驗采用了0.96寸OLED的屏幕(通訊方式IIC),4個接線柱(SCL,SDA,GND,VCC); ????????IIC通訊實現(xiàn)方式: IIC(Inter-Integrated Circuit)總線是一種由 PHILIPS 公司開發(fā)的兩線式串行總線,用于連接微控制器及其外圍設(shè)備。它是由數(shù)據(jù)線 SDA 和時鐘 SCL 構(gòu)成的串行總線,可發(fā)送和接收數(shù)據(jù)。高速 IIC 總線一般可達 400kbps 以上。

模擬IIC通訊:

????????I2C 是支持多從機的,也就是一個 I2C 控制器下可以掛多個 I2C 從設(shè)備,這些不同的 I2C從設(shè)備有不同的器件地址,這樣 I2C 主控制器就可以通過 I2C 設(shè)備的器件地址訪問指定的 I2C設(shè)備了。SDA 和SCL 這兩根線必須要接一個上拉電阻,一般是 4.7K。其余的 I2C 從器件都掛接到 SDA 和 SCL 這兩根線上,這樣就可以通過 SDA 和 SCL 這兩根線來訪問多個 I2C設(shè)備。

I2C 協(xié)議:(1)起始位;(2)停止位;(3)數(shù)據(jù)傳輸;(4)應(yīng)答信號;(5)I2C 寫時序;(6)I2C 讀時序

I2C 寫時序

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

1)、開始信號。

2)、發(fā)送 I2C 設(shè)備地址,每個 I2C 器件都有一個設(shè)備地址,通過發(fā)送具體的設(shè)備地址來決

定訪問哪個 I2C 器件。這是一個 8 位的數(shù)據(jù),其中高 7 位是設(shè)備地址,最后 1 位是讀寫位,為

1 的話表示這是一個讀操作,為 0 的話表示這是一個寫操作。

3)、 I2C 器件地址后面跟著一個讀寫位,為 0 表示寫操作,為 1 表示讀操作。

4)、從機發(fā)送的 ACK 應(yīng)答信號。

5)、重新發(fā)送開始信號。

6)、發(fā)送要寫寫入數(shù)據(jù)的寄存器地址。

7)、從機發(fā)送的 ACK 應(yīng)答信號。

8)、發(fā)送要寫入寄存器的數(shù)據(jù)。

9)、從機發(fā)送的 ACK 應(yīng)答信號。

10)、停止信號。

I2C 時序

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

I2C 單字節(jié)讀時序比寫時序要復(fù)雜一點,讀時序分為 4 大步,第一步是發(fā)送設(shè)備地址,第二步是發(fā)送要讀取的寄存器地址,第三步重新發(fā)送設(shè)備地址,最后一步就是 I2C 從器件輸出要讀取的寄存器值,我們具體來看一下這幾步。

1)、主機發(fā)送起始信號。

2)、主機發(fā)送要讀取的 I2C 從設(shè)備地址。

3)、讀寫控制位,因為是向 I2C 從設(shè)備發(fā)送數(shù)據(jù),因此是寫信號。

4)、從機發(fā)送的 ACK 應(yīng)答信號。

5)、重新發(fā)送 START 信號。

6)、主機發(fā)送要讀取的寄存器地址。

7)、從機發(fā)送的 ACK 應(yīng)答信號。

8)、重新發(fā)送 START 信號。

9)、重新發(fā)送要讀取的 I2C 從設(shè)備地址。

10)、讀寫控制位,這里是讀信號,表示接下來是從 I2C 從設(shè)備里面讀取數(shù)據(jù)。

11)、從機發(fā)送的 ACK 應(yīng)答信號。

12)、從 I2C 器件里面讀取到的數(shù)據(jù)。

13)、主機發(fā)出 NO ACK 信號,表示讀取完成,不需要從機再發(fā)送 ACK 信號了。

14)、主機發(fā)出 STOP 信號,停止 I2C 通信。

????????3、JDY-31藍牙模塊

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

?????????市場上藍牙模塊有很多,常見的JDY-xx,HC-xx等系列。其實看似高級的藍牙功能背后就是簡單的串口通訊; ?

????????USART 的全稱是 Universal Synchronous/Asynchronous Receiver/Transmitter,也就是同步/異步串行收發(fā)器。相比 UART 多了一個同步的功能,在硬件上體現(xiàn)出來的就是多了一條時鐘線。一般 USART 是可以作為 UART 使用的,也就是不使用其同步的功能。

串口通訊協(xié)議:

????????數(shù)據(jù)包:串口通訊的數(shù)據(jù)包由發(fā)送設(shè)備通過自身的TXD接口傳輸?shù)浇邮赵O(shè)備得RXD接口,在協(xié)議層中規(guī)定了數(shù)據(jù)包的內(nèi)容,具體包括起始位、主體數(shù)據(jù)(8位或9位)、校驗位以及停止位,通訊的雙方必須將數(shù)據(jù)包的格式約定一致才能正常收發(fā)數(shù)據(jù)。

具體如圖所示:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????波特率:由于異步通信中沒有時鐘信號,所以接收雙方要約定好波特率,即每秒傳輸?shù)拇a元個數(shù),以便對信號進行解碼,常見的波特率有4800、9600、115200等。STM32中波特率的設(shè)置通過串口初始化結(jié)構(gòu)體來實現(xiàn)。

? ? ? ? 注意:MCU設(shè)置的波特率大小要與藍牙APP設(shè)置的大小一致!

? ? ? ? 4、6線減速電機(帶編碼器)模塊:

????????市面上電機有很多,常用的有步進電機,直流減速電機,伺服電機等等; 編碼器:用來測量電機轉(zhuǎn)速的儀器元件,常見的有:霍爾編碼器,光電編碼器等 電機的驅(qū)動原理很簡單,給電壓差即可使得電機轉(zhuǎn)動,調(diào)速則利用PWM調(diào)節(jié)發(fā)。

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????編碼器原理: 編碼器是一種將角位移或者角速度轉(zhuǎn)換成一串電數(shù)字脈沖的旋轉(zhuǎn)式傳感器。 編碼器工作原理: 霍爾編碼器是有霍爾馬盤和霍爾元件組成。霍爾馬盤是在一定直徑的圓板上等分的布置有不同的磁極。霍爾馬盤與電動機同軸,電動機旋轉(zhuǎn)時,霍爾元件檢測輸出若干脈沖信號,為判斷轉(zhuǎn)向,一般輸出兩組存在一定相位差的方波信號。

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

?????????注意:通過判斷A與B相哪一位在前,即可判斷出正轉(zhuǎn)還是反轉(zhuǎn)

二、CubexMX設(shè)置

????????使用的MCU為stm32f103c8t6:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????RCC:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

?????????SYS:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

? ? ? ? 注意:Debug這里一定要設(shè)置成Serial Wire否則可能出現(xiàn)芯片自鎖

????????GPIO設(shè)置:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????定時TIM2用來測速與測量正轉(zhuǎn)反轉(zhuǎn)(計數(shù)器模式)

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

? ? ? ? ?定時3:PWM調(diào)節(jié)

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????I2C:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32?????????USART1:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

? ? ? ? 之后按照自己習(xí)慣生成初始化文件

三、代碼

????????自動生成的:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

????????需要自己編寫的:

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

? ? ? ? I2C代碼:

#include "oled.h"
#include "asc.h"
#include "main.h"
void WriteCmd(unsigned char I2C_Command)//???
 {
	HAL_I2C_Mem_Write(&hi2c2,OLED0561_ADD,COM,I2C_MEMADD_SIZE_8BIT,&I2C_Command,1,100);
 }
		
void WriteDat(unsigned char I2C_Data)//???
 {
		HAL_I2C_Mem_Write(&hi2c2,OLED0561_ADD,DAT,I2C_MEMADD_SIZE_8BIT,&I2C_Data,1,100);
  }
	void OLED_Init(void)
{
	HAL_Delay(100); //????????
	
	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //???? 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set com pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel
}

void OLED_SetPos(unsigned char x, unsigned char y) //???????
{ 
	WriteCmd(0xb0+y);
	WriteCmd(((x&0xf0)>>4)|0x10);
	WriteCmd((x&0x0f)|0x01);
}

void OLED_Fill(unsigned char fill_Data)//????
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		WriteCmd(0xb0+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<128;n++)
			{
				WriteDat(fill_Data);
			}
	}
}


void OLED_CLS(void)//??
{
	OLED_Fill(0x00);
}

void OLED_ON(void)
{
	WriteCmd(0X8D);  //?????
	WriteCmd(0X14);  //?????
	WriteCmd(0XAF);  //OLED??
}

void OLED_OFF(void)
{
	WriteCmd(0X8D);  //?????
	WriteCmd(0X10);  //?????
	WriteCmd(0XAE);  //OLED??
}

// Parameters     : x,y -- ?????(x:0~127, y:0~7); ch[] -- ???????; TextSize -- ????(1:6*8 ; 2:8*16)
// Description    : ??codetab.h??ASCII??,?6*8?8*16???
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
	unsigned char c = 0,i = 0,j = 0;
	switch(TextSize)
	{
		case 1:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 126)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
					WriteDat(F6x8[c][i]);
				x += 6;
				j++;
			}
		}break;
		case 2:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 120)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i]);
				OLED_SetPos(x,y+1);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i+8]);
				x += 8;
				j++;
			}
		}break;
	}
}

// Parameters     : x,y -- ?????(x:0~127, y:0~7); N:???.h????
// Description    : ??ASCII_8x16.h????,16*16??
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
}

// ????????????????,????????“??——???——????”??????ascll.h?????(????)
//???????:x:?????  
//								y:???(??0-7)  
//								begin:????????????????ascll.c???????  
//                num:????????
//                ????“??”,??????????????????0,1,???0,??????,??:x:0,y:2,begin:0,num:2
void OLED_ShowCN_STR(u8 x , u8 y , u8 begin , u8 num)
{
	u8 i;
	for(i=0;i<num;i++){OLED_ShowCN(i*16+x,y,i+begin);}    //OLED????
}

// Parameters     : x0,y0 -- ?????(x0:0~127, y0:0~7); x1,y1 -- ?????(???)???(x1:1~128,y1:1~8)
// Description    : ??BMP??
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
		{
			WriteDat(BMP[j++]);
		}
	}
}

void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{      	
	unsigned char c=0,i=0;	
		c=chr-' ';//???????			
		if(x>128-1){x=0;y=y+2;}
		if(Char_Size ==16)
			{
			OLED_SetPos(x,y);	
			for(i=0;i<8;i++)
			WriteDat(F8X16[c*16+i]);
			OLED_SetPos(x,y+1);
			for(i=0;i<8;i++)
			WriteDat(F8X16[c*16+i+8]);
			}
			else {	
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
				WriteDat(F6x8[c][i]);
				
			}
}
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}	
//??2???
//x,y :????	 
//len :?????
//size:????
//mode:??	0,????;1,????
//num:??(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
} 

? ? ? ? ?UART代碼:

#include "uart.h"

uint8_t USART1_RX_BUF[USART1_REC_LEN];//????,??USART_REC_LEN???.
uint16_t USART1_RX_STA=0;//??????//bit15:??????,bit14~0:??????????
uint8_t USART1_NewData;//?????????1????????

extern int flag;

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//????????
{
    if(huart ==&huart1)
    {
        if((USART1_RX_STA&0x8000)==0)//?????
        {
            if(USART1_NewData==0x5A)//????0x5A
            {
                 USART1_RX_STA|=0x8000;   //?????,?USART2_RX_STA??bit15(15?)?1
            }
            else
            {
                   USART1_RX_BUF[USART1_RX_STA&0X7FFF]=USART1_NewData; 

							if(USART1_RX_BUF[1] == 0x01)
							{
								flag = 2;
							}
							
                   USART1_RX_STA++;  //???????1
                   if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//??????,??????

            }
        }
        HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); 

    }
}

?????????常規(guī)的編寫如上,但是本人的MCU存在問題,單片機并未接收到預(yù)設(shè)的數(shù)據(jù)。

????????所以,本人項目中采用了下方代碼:

#include "uart.h"

uint8_t USART1_RX_BUF[USART1_REC_LEN];//????,??USART_REC_LEN???.
uint16_t USART1_RX_STA=0;//??????//bit15:??????,bit14~0:??????????
uint8_t USART1_NewData;//?????????1????????

extern int flag;

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//????????
{
    if(huart ==&huart1)
    {
                              
              USART1_RX_BUF[USART1_RX_STA&0X7FFF]=USART1_NewData; 					
              USART1_RX_STA++;  //???????1
			
                   if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//??????,??????
			
							if(USART1_RX_BUF[USART1_RX_STA-4] == 0xA0)
							{
								flag = 1;
							}
							if(USART1_RX_BUF[USART1_RX_STA-4] == 0x90)
							{
								flag = 2;
							}
							if(USART1_RX_BUF[USART1_RX_STA-4] == 0xD0)
							{
								flag = 3;
							}
							if(USART1_RX_BUF[USART1_RX_STA-4] == 0x88)
							{
								flag = 4;
							}
							if(USART1_RX_BUF[USART1_RX_STA-4] == 0x48)
							{
								flag = 5;
							}							
        
        HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); 

    }
}

?????????如果大家自己使用的花,可以根據(jù)自己的藍牙APP寫這段程序,有問題歡迎留言

? ? ? ? Motor代碼:

#include "motor.h"

void MOTOR_GO()
{
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1,3000);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}

void MOTOR_BACK()
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
}

void MOTOR_STOP()
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
}

void MOTOR_UP()
{
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1,1);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}

void MOTOR_DOWN()
{
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1,400);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}

? ? ? ? ?PID:

PID算法:

PID分為位置型和增量型

增量型即通過 u(k)-u(k-1) 從而得出式子:

公式的第一部分是比例式 是為了讓值按一定比例達到目標(biāo)值;

第二部分是積分值,正值,在計算的過程中往往會受到環(huán)境等一些其他因素的影響,導(dǎo)致值不能到達目標(biāo)值;

第三部分是微分值,通常是負(fù)值,后一次偏差值往往小于前一次偏差值,目的是為了防止值增加過大,通常起一個阻礙的作用;

直流減速電機的控制,STM32開發(fā),c語言,嵌入式硬件,stm32

? ? ? ? PID代碼:

#include "pid.h"
#include "tim.h"
#include "main.h"
#include "math.h"
#include "i2c.h"
#include "oled.h"

unsigned int MotorSpeed;		//è???±?á?£?μ??úμ±?°×a?ù
int SpeedTarget = 750;				//??±ê×a?ù
int MotorOutput;						//μ??úê?3?

//1.à?ó?TIM2????μ??ú×a?ù

void GetMotorSpeed(void)
{
//		int CaptureNumber =	(short)__HAL_TIM_GET_COUNTER(&htim2);	  //HAL?aoˉêy??????3?′?êy
//	
//	//μ??ú×a?ù×a??Speed=1s?úμ???3?êy/44(ò?è|11??D?o?£?4±??μ·¨)/34???ù±è
//		int MotorSpeed=CaptureNumber*20/44/34*2*3.14*3;
//		OLED_ShowNum(40,0,MotorSpeed,4,16);
//	
//		__HAL_TIM_GET_COUNTER(&htim2) = 0;													//??êy?÷??á?
	
	int CaptureNumber =	(short)__HAL_TIM_GET_COUNTER(&htim2);	  //???????
	__HAL_TIM_GET_COUNTER(&htim2) = 0;
//	int Speed=CaptureNumber*5/44/34*2*3.14*3;
    int 	Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); 		
		if(Direction == 1)
		{
				CaptureNumber -= 65535;
		}
	MotorSpeed=CaptureNumber;
	OLED_ShowNum(40,0,MotorSpeed,4,16);
	HAL_Delay(100);
	OLED_CLS();
//	__HAL_TIM_GET_COUNTER(&htim2) = 0;
}

//2.??á?ê?PID?????÷£¨PID3£??·??a????PIDoí??á?ê?PID£?

int Error_Last,Error_Prev;		//é?′??ó2?£?é?é?′??ó2?
int Pwm_add,Pwm;							//PWM??á?,PWM????±è

int Kp = 5, Ki = 3, Kd = 1;//PID??·¨?μêy£???μ?ààDí£?D????????üá|ò?°?ê±?¨òé??Dí£??ò??*1024

int SpeedInnerControl(int Speed,int Target)		//?ù?è?ú?·????
{
    int Error = Target - Speed;		//?ó2? = ??±ê?ù?è - êμ?ê?ù?è 

    Pwm_add = Kp * (Error - Error_Last) + 										//±èày
							Ki * Error +																		//?y·?
							Kd * (Error - 2.0f * Error_Last + Error_Prev);	//?¢·?


    Pwm += Pwm_add;		//ê?3?á?=?-ê?á?+??á?
	
		Error_Prev = Error_Last;	//±£′?é?é?′??ó2?
    Error_Last = Error;				//±£′?é?′??ó2?

    if(Pwm > 4999) Pwm = 3000;	//?T??é????T£?·à?1PWM3?3?á?3ì
    if(Pwm <-4999) Pwm =-3000;

    return Pwm;	//·μ??ê?3??μ
}

//3.μ??ú×a?ùó?·??òμ?oˉêy£¨PID????£?

void SetMotorVoltageAndDirection(int Pwm)
{
    if(Pwm < 0)			//è?1?PWMD?óú0
    {        
			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
        
			Pwm = (-Pwm);			//PWM???üè??y?μ£?è?1??a?oêy£??±?óè?·′
        
			__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, Pwm);	//PWMμ÷?ù
			
    } else
    {
			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
			
      __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, Pwm);	//PWMμ÷?ù
    }
}

void ModePID()
{
  GetMotorSpeed();
  MotorOutput = SpeedInnerControl(MotorSpeed,SpeedTarget);
  SetMotorVoltageAndDirection(MotorOutput);
}

? ? ? ? ?主函數(shù)代碼:

 while (1)
 {  
    		 switch(flag)    
    		 {
    		 case(1):MOTOR_GO();break;
    		 case(2):MOTOR_BACK();break;
    		 case(3):MOTOR_STOP();break;
    		 case(4):MOTOR_UP();break;
    		 case(5):ModePID();break;
    		 default:break;
    		 }     
		
    /* USER CODE END WHILE */
		if(flag != 5)
		{
		int CaptureNumber =	(short)__HAL_TIM_GET_COUNTER(&htim2);	  //???????
		__HAL_TIM_GET_COUNTER(&htim2) = 0;
//    int 	Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); 
		//μ??ú×a?ù×a??Speed=1s?úμ???3?êy/44(ò?è|11??D?o?£?4±??μ·¨)/34???ù±è
//		int Speed=CaptureNumber*5/44/34*2*3.14*3;
    int 	Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); 		
		if(Direction == 1)
		{
				CaptureNumber -= 65535;
		}
			
		int Speed=CaptureNumber;
    OLED_ShowNum(40,0,Speed,5,16);
		HAL_Delay(100);
		OLED_CLS();			
		}
		
    int 	Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); 			
		OLED_ShowCN_STR(0,0,0,3);
//    OLED_ShowNum(40,0,Speed,4,16);
		OLED_ShowStr(90,0,"cm/s",2);
		OLED_ShowCN_STR(0,3,3,2);		
    if(Direction==0)
		{
			OLED_ShowCN_STR(40,3,5,2);	
		}
		if(Direction==1)
		{
			OLED_ShowCN_STR(40,3,7,2);
		}		
//		HAL_Delay(1000);
//		OLED_CLS();
    /* USER CODE BEGIN 3 */
  }

????????藍牙APP源代碼以及技術(shù)論文:鏈接:https://pan.baidu.com/s/1-rbicxuyLVCq6rglCWcJTg?
提取碼:huzm文章來源地址http://www.zghlxwxcb.cn/news/detail-829954.html

到了這里,關(guān)于基于stm32的減速直流電機PID算法控制的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 直流減速編碼電機的使用(STM32f103c8t6)L298N電機驅(qū)動模塊

    直流減速編碼電機的使用(STM32f103c8t6)L298N電機驅(qū)動模塊

    直接減速電機就是在直流電機上加上霍爾編碼器,霍爾編碼器可用于電機轉(zhuǎn)動的測速,A、B相會產(chǎn)生相位相差90°的方波信號。stm32可以使用硬件資源或者軟件模擬來捕獲編碼器信號。這里我介紹的是stm32自帶的編碼器模式來使用直流減速電機。 以下是直流減速電機的商品圖 ?

    2024年02月13日
    瀏覽(56)
  • STM32增量式pid直流電機調(diào)速(內(nèi)附源碼)

    STM32增量式pid直流電機調(diào)速(內(nèi)附源碼)

    ??????? 目錄 一. 1.硬件組成 2.模塊分析 ? ? ? ? 1.TB6612電機驅(qū)動模塊 ????????2.直流減速電機 ????????3.電源穩(wěn)壓模塊 二.接線 三.代碼思路講解(詳見源碼) 四.STM32cubmx配置 1.系統(tǒng)基礎(chǔ)配置:(重要) 2.電機旋轉(zhuǎn)方向引腳配置 3.TIM1每10ms觸發(fā)一次的定時器中斷 4.TI

    2024年02月16日
    瀏覽(28)
  • PID模塊化__以stm32直流電機速度為例

    PID模塊化__以stm32直流電機速度為例

    本篇使用到的基于這個STM32CubeMX 直流電機PID速度控制、HAL庫、cubemx、PID、速度控制、增量式 由于上次使用的pid沒有模塊化,當(dāng)多出使用pid的時候就會很麻煩 所以這次使用的模塊化的 在main.c或者其他位置創(chuàng)建pid的變量 注意一定要在pid計算之前初始化 all_moto_pid_init ,不然會導(dǎo)

    2024年02月14日
    瀏覽(22)
  • STM32單片機直流電機PID速度控制正反轉(zhuǎn)控制(霍爾磁鐵測速)LCD1602
  • STM32CubeMX 直流電機串級PID位置速度控制、HAL庫、cubemx、PID、串級PID、位置控制、速度控制、雙環(huán)控制

    STM32CubeMX 直流電機串級PID位置速度控制、HAL庫、cubemx、PID、串級PID、位置控制、速度控制、雙環(huán)控制

    提示:本文章的串級PID位置速度控制,是在前兩篇文章速度控制,位置控制的基礎(chǔ)上實現(xiàn)的,這一章節(jié)中不需要額外的cubemx的配置,只需要寫簡單的代碼即可,復(fù)雜的地方在于串級pid的調(diào)試過程。 pid是我們在學(xué)習(xí)單片機中首先要學(xué)會的控制算法,而串級pid又是在單pid的基礎(chǔ)上

    2024年02月14日
    瀏覽(31)
  • 【32單片機學(xué)習(xí)】(3)霍爾編碼器減速直流電機控制及測速

    【32單片機學(xué)習(xí)】(3)霍爾編碼器減速直流電機控制及測速

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 目錄 前言 1.實驗現(xiàn)象 2.實驗接線及原理圖 接線圖 原理圖? 電機接線圖 3.代碼部分 1.主函數(shù)? main.c 2.按鍵部分? ?key.c ?key.h pwm代碼? ?pwm.c ?pwm.h 電機驅(qū)動? ?motor.c? ?motor.h ?OLED顯示 oled.c oled.h? 編碼器

    2024年02月11日
    瀏覽(36)
  • 基于51單片機的直流電機轉(zhuǎn)速顯示+加速減速啟停

    基于51單片機的直流電機轉(zhuǎn)速顯示+加速減速啟停

    做了一個實戰(zhàn)項目,這個實戰(zhàn)項目主要是實現(xiàn)對直流電機轉(zhuǎn)速的控制,可以實現(xiàn)電機加速,減速,報警、啟停以及顯示轉(zhuǎn)速。在本電路的基礎(chǔ)上也可以進行一些拓展改變電機正反轉(zhuǎn)的狀態(tài),只需要外加一個按鍵和修改部分程序即可,在文章的最后會對拓展進行一個說明。基礎(chǔ)

    2023年04月27日
    瀏覽(20)
  • 基于STM32的智能巡檢小車系統(tǒng)設(shè)計--STM32最小系統(tǒng)、直流電機、直流電源模塊設(shè)計

    基于STM32的智能巡檢小車系統(tǒng)設(shè)計--STM32最小系統(tǒng)、直流電機、直流電源模塊設(shè)計

    作者:車 郵箱:692604135@qq.com 學(xué)校:西安工程大學(xué)碩士研究生 方向:機器視覺、圖像分割、深度學(xué)習(xí) 在介紹具體實現(xiàn)功能之前,需要介紹以下模塊。 本課題選擇的單片機是ST(意法半導(dǎo)體)開發(fā)的STM32F407VET6。 這是一款采用Corte-M4為內(nèi)核的高性能32位ARM微控制器。該芯片支持

    2024年02月10日
    瀏覽(96)
  • 基于STM32的300W無刷直流電機驅(qū)動方案

    基于STM32的300W無刷直流電機驅(qū)動方案

    近些年,由于無刷直流電機大規(guī)模的研發(fā)和技術(shù)的逐漸成熟,已逐步成為工業(yè)用電機的發(fā)展主流。圍繞降低生產(chǎn)成本和提高運行效率,各大廠商也提供不同型號的電機以滿足不同驅(qū)動系統(tǒng)的需求?,F(xiàn)階段已經(jīng)在紡織、冶金、印刷、自動化生產(chǎn)流水線、數(shù)控機床等工業(yè)生產(chǎn)方面

    2024年02月12日
    瀏覽(23)
  • 基于STM32單片機的直流電機PWM調(diào)速(數(shù)碼管顯示)(Proteus仿真+程序)

    基于STM32單片機的直流電機PWM調(diào)速(數(shù)碼管顯示)(Proteus仿真+程序)

    ? ? ? 由 STM32單片機+數(shù)碼管顯示模塊+鍵盤模塊+L298N電機驅(qū)動模塊+直流電機 1、采用STM32F103單片機為主控制器 2、四個按鍵,分別為啟動/暫停、方向切換、加速、減速功能 3、數(shù)碼管顯示PWM占空比和電機轉(zhuǎn)動方向(0正轉(zhuǎn),1反轉(zhuǎn)) 注意:proteus8.11版本才能打開 ? 24、基于STM32單

    2024年02月11日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包