基于stm32的减速直流电机PID算法控制_直流减速电机的控制

7)、从机发送的 ACK 应答信号。

8)、发送要写入寄存器的数据。

9)、从机发送的 ACK 应答信号。

10)、停止信号。

I2C 时序

4eb171668a0b40cebded99320af6c4be.png

I2C 单字节读时序比写时序要复杂一点,读时序分为 4 大步,第一步是发送设备地址,第二步是发送要读取的寄存器地址,第三步重新发送设备地址,最后一步就是 I2C 从器件输出要读取的寄存器值,我们具体来看一下这几步。

1)、主机发送起始信号。

2)、主机发送要读取的 I2C 从设备地址。

3)、读写控制位,因为是向 I2C 从设备发送数据,因此是写信号。

4)、从机发送的 ACK 应答信号。

5)、重新发送 START 信号。

6)、主机发送要读取的寄存器地址。

7)、从机发送的 ACK 应答信号。

8)、重新发送 START 信号。

9)、重新发送要读取的 I2C 从设备地址。

10)、读写控制位,这里是读信号,表示接下来是从 I2C 从设备里面读取数据。

11)、从机发送的 ACK 应答信号。

12)、从 I2C 器件里面读取到的数据。

13)、主机发出 NO ACK 信号,表示读取完成,不需要从机再发送 ACK 信号了。

14)、主机发出 STOP 信号,停止 I2C 通信。

3、JDY-31蓝牙模块

5d17fadf15304e3b83d8cd1cda15fec9.png0a658fa91da4497aa2f79b705929dedb.png

市场上蓝牙模块有很多,常见的JDY-xx,HC-xx等系列。其实看似高级的蓝牙功能背后就是简单的串口通讯

USART 的全称是 Universal Synchronous/Asynchronous Receiver/Transmitter,也就是同步/异步串行收发器。相比 UART 多了一个同步的功能,在硬件上体现出来的就是多了一条时钟线。一般 USART 是可以作为 UART 使用的,也就是不使用其同步的功能。

串口通讯协议:

数据包:串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

具体如图所示:

d48a572df6514325bcf8e6e4563a7261.png

波特率:由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。

注意:MCU设置的波特率大小要与蓝牙APP设置的大小一致!

4、6线减速电机(带编码器)模块:

市面上电机有很多,常用的有步进电机,直流减速电机,伺服电机等等; 编码器:用来测量电机转速的仪器元件,常见的有:霍尔编码器,光电编码器等 电机的驱动原理很简单,给电压差即可使得电机转动,调速则利用PWM调节发。

0ab46a4a62884051969e1d0542425de9.png

编码器原理: 编码器是一种将角位移或者角速度转换成一串电数字脉冲的旋转式传感器。 编码器工作原理: 霍尔编码器是有霍尔马盘和霍尔元件组成。霍尔马盘是在一定直径的圆板上等分的布置有不同的磁极。霍尔马盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。

28535d8124d54c05aee35e73ea017766.png

476a459656cd4486a30d43e47a404368.png

注意:通过判断A与B相哪一位在前,即可判断出正转还是反转

二、CubexMX设置

使用的MCU为stm32f103c8t6:

1902f6d03eb540229a5742619c6ba01e.png

RCC:

f13d2afd3ccb429590fb408805b1ea4a.png

SYS:

a37986c672e04dfab695fe1a65a36bc8.png

注意:Debug这里一定要设置成Serial Wire否则可能出现芯片自锁

GPIO设置:

bdc68e160d0d430f9c8e4e4973c2f01d.png

定时TIM2用来测速与测量正转反转(计数器模式)

82ccfcd4a8cc4b429a9c31a3ab92f154.png

定时3:PWM调节

ea2cc40b70c34320b608219f8c6491cb.png

I2C:

0cbd996c978146208a517ab020b090e4.png         USART1:

43bdbb7ae45f4244ac655269bb0497da.png

之后按照自己习惯生成初始化文件

三、代码

自动生成的:

8183cb7e16d54f95a9d149ff143843b2.png

需要自己编写的:

17d379d74a26416aa0ea9eb11005c69b.png

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); 

    }
}

常规的编写如上,但是本人的MCU存在问题,单片机并未接收到预设的数据。

所以,本人项目中采用了下方代码:

#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); 

    }
}

如果大家自己使用的花,可以根据自己的蓝牙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:

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-zRcUITqH-1715684903479)]

[外链图片转存中…(img-QyEpRcAG-1715684903480)]

[外链图片转存中…(img-V7L0DreI-1715684903480)]

[外链图片转存中…(img-MEzUgELy-1715684903481)]

[外链图片转存中…(img-wvrgmUFw-1715684903481)]

[外链图片转存中…(img-LRUPzQKP-1715684903482)]

[外链图片转存中…(img-qmG5BHjn-1715684903482)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值