“无限交互,全新驾驶体验!智能语音小车,与您共同开创未来出行。”#51单片机最终项目《智能语音小车》【上】

"无限交互,全新驾驶体验!智能语音小车,与您共同开创未来出行。”#51单片机最终项目《智能语音小车》【上】

    • 前言
    • 预备知识
    • 1. L9110S电机控制器接线
      • 1.1 L9110S概述
      • 1.2 L9110S IO口描述
      • 1.3 L9110S 实物图
      • 1.4 L9110S与单片机接线
    • 2. L9110前后左右控制小车
      • 2.1 L9110前后左右控制小车
      • 2.1分别用高低电平测试B-1A和B-1B L9110电机驱动模块引脚,A-1A和A-1B L9110电机驱动模块引脚。
      • 2.2 将测试结果封装函数
      • 2.3封装前后左右行走函数
      • 2.4主函数内进行间隔2秒调用前后左右函数
      • 2.5完整程序代码
    • 3.电机相关代码封装_分文件
      • 3.1电机相关代码封装_分文件核心思路
      • 3.2将控制电机前进,后退,向左,向右的函数封装到电机对应的C文件中。
      • 3.3建立电机头文件,里面声明电机对应C文件中的函数
      • 3.4将延时2秒的函数封装到延时C文件中
      • 3.5建立延时头文件,里面声明延时C文件中的函数。
      • 3.6主函数中包含电机头文件和延时头文件即可完美运行程序
    • 4.串口控制小车
      • 4.1串口控制小车核心思路
      • 4.2找到wifi开灯项目中优化8266,捕获联网失败的状态工程打开
      • 4.3拷贝串口使用相关声明定义,串口初始化函数,串口中断函数,建立串口C文件和头文件。
      • 4.4在电机对应C文件中构造小车停止函数
      • 4.5在串口中断函数中通过接收指令操作小车运行
      • 4.6串口C文件代码
    • 5.手机通过蓝牙控制小车_自定义按键
      • 5.1手机通过蓝牙控制小车_自定义按键核心思路
      • 5.2将蓝牙模块正确接线连接51单片机串口
      • 5.3给51单片机,蓝牙模块上电,打开手机APP HC蓝牙助手进行连接
      • 5.4通过自定义按钮使HC蓝牙助手发送相应控制小车指令
    • 6.蓝牙小车的点动控制
      • 6.1蓝牙小车的点动控制核心思路
      • 6.2在主C文件主函数while(1)死循环中调用电机停止函数。
      • 6.3在串口中断函数中接收指令并执行调用电机相关函数时延时10毫秒实现点动
      • 6.4通过串口助手自动发送模拟长按一直发送一直运行的状态。
    • 7.PWM软件调速
      • 7.1 PWM软件调速核心思路
      • 7.2打开感应开盖垃圾桶项目_舵机编程实战工程主C文件
      • 7.3在工程内新建time0.c文件
      • 7.4拷贝相关变量,定时器0初始化函数,定时器零中断函数
      • 7.5修改定时器0中断函数,使之调用电机控制函数,实现调速
      • 7.6建立time.h文件
      • 7.7主C文件内每隔1.5秒改变速度变量,使小车电机变速
      • 7.8 PWM软件调速原理图
    • 8.左右电机的各自调速管理
      • 8.1左右电机的各自调速管理核心思路
      • 8.2在motor.c文件内建立单独控制左右轮前进和停止函数,并在motor.h文件中声明。
      • 8.3建立time1.c和time1.h文件用于对右轮的控制和初始化。
      • 8.4修改time0.c为左轮控制
      • 8.5主C文件内每隔1.5秒改变左右轮速度变量,使小车左右轮电机差速运行
    • 结束语

前言

  本篇博文介绍的是用51单片机的最终项目《智能语音小车》【上】,包含L9110S电机控制器接线, L9110前后左右控制小车,电机相关代码封装–分文件,串口控制小车,手机通过蓝牙控制小车–自定义按键,蓝牙小车的点动控制,PWM软件调速,左右电机的各自调速管理。看到这篇博文的朋友,可以先赞再看吗?

预备知识

  一、需要我之前写的所有博文的知识,如果还没看我之前的的博文,可以去看看后再看本篇博文
在这里插入图片描述
  二、C变量
  三、基本输入输出
  四、流程控制
  五、函数

  六、指针
  七、字符串

  如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!

1. L9110S电机控制器接线

1.1 L9110S概述

  L9110S是一种双路H桥驱动器芯片,通常用于控制直流电机或步进电机。该芯片具有内置的双H桥驱动器,可实现电机的双向控制。它可以通过控制输入信号来控制电机的转向和速度,并且通常被广泛应用于各种小型电动车辆、机器人以及其他需要电机控制的项目中。L9110S还具有过流保护功能,能够保护电机和驱动器免受损坏。

1.2 L9110S IO口描述

  以下资料来源官方,但是不对

  IA1输入高电平,IA1输入低电平,【OA1 OB1】电机正转;
  IA1输入低电平,IA1输入高电平,【OA1 OB1】电机反转;
  IA2输入高电平,IA2输入低电平,【OA2 OB2】电机正转;
  IA2输入低电平,IA2输入高电平,【OA2 OB2】电机反转;

1.3 L9110S 实物图

在这里插入图片描述

1.4 L9110S与单片机接线

  • 注意:电源线千万别接错,不然会在0.5秒内烧坏模块,电源正常接通电源指示灯会亮。

在这里插入图片描述

2. L9110前后左右控制小车

2.1 L9110前后左右控制小车

  • 分别用高低电平测试B-1AB-1B ``L9110电机驱动模块引脚,A-1AA-1B ``L9110电机驱动模块引脚。
  • 将测试结果封装函数
  • 封装前后左右行走函数

2.1分别用高低电平测试B-1A和B-1B L9110电机驱动模块引脚,A-1A和A-1B L9110电机驱动模块引脚。

  • B-1A1B-1B0,将A-1A1A-1B0。看一下电机的转向。

  • 代码体现

RightControA = 1;
RightControB = 0;LeftControA  = 1;
LeftControB  = 0;
  • 测试结果为小车向后跑,也就电机反转。

2.2 将测试结果封装函数

  • 测试结果为小车向前跑,封装向前函数。

  • 代码体现。

void goBack()
{RightControA = 1;RightControB = 0;LeftControA  = 1;LeftControB  = 0;
}

2.3封装前后左右行走函数

  • 向前函数封装思路

  将向后函数的高低电平兑换就实现了向前功能。

  • 代码体现
void goFront()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 1;
}
  • 向左和向右行走函数思路

  如果要实现向左行走就将控制左轮的引脚置零,实现向右行走就将控制右轮的引脚置零。这样就实现了向左和向右行走。

  • 代码体现
void goLeft()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 0;
}void goRight()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 1;
}

2.4主函数内进行间隔2秒调用前后左右函数

  • 代码体现
void main()
{while(1){goFront();Delay2000ms();goBack();Delay2000ms();goLeft();Delay2000ms();goRight();Delay2000ms();}
}

2.5完整程序代码

#include "reg52.h"
#include "intrins.h"sbit RightControA = P3^2;         //右轮控制A
sbit RightControB = P3^3;         //右轮控制B
sbit LeftControA  = P3^4;         //左轮控制A
sbit LeftControB  = P3^5;         //左轮控制Bvoid Delay2000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 15;j = 2;k = 235;do{do{while (--k);} while (--j);} while (--i);
}void goLeft()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 0;
}void goRight()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 1;
}void goBack()
{RightControA = 1;RightControB = 0;LeftControA  = 1;LeftControB  = 0;
}void goFront()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 1;
}void main()
{while(1){goFront();Delay2000ms();goBack();Delay2000ms();goLeft();Delay2000ms();goRight();Delay2000ms();}
}

3.电机相关代码封装_分文件

3.1电机相关代码封装_分文件核心思路

  • 将控制电机前进,后退,向左,向右的函数封装到电机对应的C文件中。

  • 建立电机头文件,里面声明电机对应C文件中的函数

  • 将延时2秒的函数封装到延时C文件中

  • 建立延时头文件,里面声明延时C文件中的函数。

  • 主函数中包含电机头文件和延时头文件即可完美运行程序

  注:此工程基于L9110前后左右控制小车工程开发

3.2将控制电机前进,后退,向左,向右的函数封装到电机对应的C文件中。

  • 将声明电机控制引脚代码移动电机对应的C文件中(具体如何建立分文件请看温湿度检测系统博文),代码体现如下。
sbit RightControA = P3^2;         //右轮控制A
sbit RightControB = P3^3;         //右轮控制B
sbit LeftControA  = P3^4;         //左轮控制A
sbit LeftControB  = P3^5;         //左轮控制B
  • 将控制电机前进,后退,向左,向右的函数移动到电机对应的C文件中。代码体现如下
void goLeft()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 0;
}void goRight()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 1;
}void goBack()
{RightControA = 1;RightControB = 0;LeftControA  = 1;LeftControB  = 0;
}void goFront()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 1;
}
  • 电机对的C文件代码截图

在这里插入图片描述

3.3建立电机头文件,里面声明电机对应C文件中的函数

  • 需要声明的函数代码如下。

void goLeft();void goRight();void goBack();void goFront();
  • 电机头文件代码截图

在这里插入图片描述

3.4将延时2秒的函数封装到延时C文件中

  • 将延时2秒的函数封装到延时C文件中代码体现
void Delay2000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 15;j = 2;k = 235;do{do{while (--k);} while (--j);} while (--i);
}
  • 延时C文件代码截图

在这里插入图片描述

3.5建立延时头文件,里面声明延时C文件中的函数。

  • 需要声明的函数代码如下。
void Delay2000ms();
  • 延时头文件代码截图

在这里插入图片描述

3.6主函数中包含电机头文件和延时头文件即可完美运行程序

  • 主函数中包含电机头文件和延时头文件代码体现
#include "motor.h"
#include "delay.h"
  • 主函数代码截图

在这里插入图片描述

4.串口控制小车

4.1串口控制小车核心思路

  • 找到wifi开灯项目中优化8266,捕获联网失败的状态工程打开主函数
  • 拷贝串口使用相关声明定义串口初始化函数串口中断函数建立串口C文件和头文件
  • 在电机对应C文件中构造小车停止函数
  • 在串口中断函数中通过接收指令操作小车运行

  注:此工程由电机相关代码封装_分文件工程开发

4.2找到wifi开灯项目中优化8266,捕获联网失败的状态工程打开

在这里插入图片描述

4.3拷贝串口使用相关声明定义,串口初始化函数,串口中断函数,建立串口C文件和头文件。

  • 拷贝串口使用相关声明定义
#include "reg52.h"
#include "string.h"
#define SIZE 32sfr AUXR = 0x8e;   //声明AUXR寄存器地址
char buffer[SIZE]; 
  • 拷贝串口初始化函数
void UartInit(void)		//自己配
{//配置串口工作方式为方式1,从只收不发改为能收能发SCON =  0x50;//配置辅助寄存器,减少电磁辐射,稳定晶振频率  AUXR =  0x01;//设置定时器工作方式为定时器1的8位自动重装TMOD &= 0x0F;TMOD |= 0x20;//设置串口波特率为9600,0误差TH1   = 0xFD;TL1   = 0xFD;//打开定时器1TR1   = 1;//打开总中断EA = 1;//打开串口中断ES = 1;
}
  • 拷贝串口中断函数
void UART_handler() interrupt 4
{//定义临时变量tmp用于判断接收的字符是否是需要的首字符。char tmp;//定义一个静态整型变量,在多次函数调用中只被执行一次初始化static int i = 0;//在串口中段函数中可以对发送接收中断标志进行处理if(RI == 1){RI = 0;     //必须软件置零tmp = SBUF;if(tmp=='W' || tmp=='O' || tmp=='L' || tmp=='F'){i = 0;}buffer[i++] = tmp;/*if(buffer[0]=='W' &&  buffer[5]=='G'){con_Net_Flag = 1;memset(buffer,'\0',SIZE);}*/if(buffer[0]=='O' && buffer[1]=='K'){at_OK_Flag   = 1;memset(buffer,'\0',SIZE);}if(buffer[0]=='F' && buffer[1] == 'A'){statusLED1();sendString(RESET);Delay1000ms();sendString(cNetwork);memset(buffer,'\0',SIZE);}//如果用1指令开灯,0指令关灯if(buffer[0]=='L' && buffer[2]=='1')  {LED1 = 0;memset(buffer,'\0',SIZE);}if(buffer[0]=='L' && buffer[2]=='0'){LED1 = 1;memset(buffer,'\0',SIZE);}if(i == SIZE){i = 0;}}if(TI);}
  • 建立串口C文件和头文件。

  一、将拷贝的所有代码整合到一起文件命名为uart.c。

#include "reg52.h"
#include "string.h"
#define SIZE 32sfr AUXR = 0x8e;   //声明AUXR寄存器地址
char buffer[SIZE]; void UartInit(void)		//自己配
{//配置串口工作方式为方式1,从只收不发改为能收能发SCON =  0x50;//配置辅助寄存器,减少电磁辐射,稳定晶振频率  AUXR =  0x01;//设置定时器工作方式为定时器1的8位自动重装TMOD &= 0x0F;TMOD |= 0x20;//设置串口波特率为9600,0误差TH1   = 0xFD;TL1   = 0xFD;//打开定时器1TR1   = 1;//打开总中断EA = 1;//打开串口中断ES = 1;
}void UART_handler() interrupt 4
{//定义临时变量tmp用于判断接收的字符是否是需要的首字符。char tmp;//定义一个静态整型变量,在多次函数调用中只被执行一次初始化static int i = 0;//在串口中段函数中可以对发送接收中断标志进行处理if(RI == 1){RI = 0;     //必须软件置零tmp = SBUF;if(tmp=='W' || tmp=='O' || tmp=='L' || tmp=='F'){i = 0;}buffer[i++] = tmp;/*if(buffer[0]=='W' &&  buffer[5]=='G'){con_Net_Flag = 1;memset(buffer,'\0',SIZE);}*/if(buffer[0]=='O' && buffer[1]=='K'){at_OK_Flag   = 1;memset(buffer,'\0',SIZE);}if(buffer[0]=='F' && buffer[1] == 'A'){statusLED1();sendString(RESET);Delay1000ms();sendString(cNetwork);memset(buffer,'\0',SIZE);}//如果用1指令开灯,0指令关灯if(buffer[0]=='L' && buffer[2]=='1')  {LED1 = 0;memset(buffer,'\0',SIZE);}if(buffer[0]=='L' && buffer[2]=='0'){LED1 = 1;memset(buffer,'\0',SIZE);}if(i == SIZE){i = 0;}}if(TI);}

  二、建立uart.h文件,里面声明串口初始化函数。

void UartInit(void);

4.4在电机对应C文件中构造小车停止函数

  • 函数思路

  将左右轮控制信号的A、B给与低电平信号,实现轮子停止转动。

  • 函数代码
void stop()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 0;
}

4.5在串口中断函数中通过接收指令操作小车运行

  • 在串口中断函数中通过接收指令操作小车运行思路

  一、将串口中断函数中的13行if(tmp\=='W' || tmp\=='O' || tmp\=='L' || tmp=='F')改为if(tmp\=='M')

  二、删除串口中断函数中19到47行代码

  三、使用if和switch嵌套进行操作小车

  四、重要bug:串口能收到指令却无法操作小车。解决办法:不在if和switch嵌套中使用清理字符串函数,在防止指针越界函数中使用

  • 在串口中断函数中通过接收指令操作小车运行代码
void UART_handler() interrupt 4
{//定义临时变量tmp用于判断接收的字符是否是需要的首字符。char tmp;//定义一个静态整型变量,在多次函数调用中只被执行一次初始化static int i = 0;//在串口中段函数中可以对发送接收中断标志进行处理if(RI == 1){RI = 0;     //必须软件置零tmp = SBUF;if(tmp=='M'){i = 0;}buffer[i++] = tmp;if(buffer[0]=='M'){switch(buffer[1]){case '1':goFront();break;case '2':goBack();break;case '3':goLeft();break;case '4':goRight();break;default:stop();break;}}if(i == SIZE){i = 0;memset(buffer,'\0',SIZE);}}if(TI);}

4.6串口C文件代码

#include "reg52.h"
#include "motor.h"
#include "string.h"#define SIZE 32sfr AUXR = 0x8e;   //声明AUXR寄存器地址
char buffer[SIZE];void UartInit()		//自己配
{//配置串口工作方式为方式1,从只收不发改为能收能发SCON =  0x50;//配置辅助寄存器,减少电磁辐射,稳定晶振频率  AUXR =  0x01;//设置定时器工作方式为定时器1的8位自动重装TMOD &= 0x0F;TMOD |= 0x20;//设置串口波特率为9600,0误差TH1   = 0xFD;TL1   = 0xFD;//打开定时器1TR1   = 1;//打开总中断EA = 1;//打开串口中断ES = 1;
}void UART_handler() interrupt 4
{//定义临时变量tmp用于判断接收的字符是否是需要的首字符。char tmp;//定义一个静态整型变量,在多次函数调用中只被执行一次初始化static int i = 0;//在串口中段函数中可以对发送接收中断标志进行处理if(RI == 1){RI = 0;     //必须软件置零tmp = SBUF;if(tmp=='M'){i = 0;}buffer[i++] = tmp;if(buffer[0]=='M'){switch(buffer[1]){case '1':goFront();break;case '2':goBack();break;case '3':goLeft();break;case '4':goRight();break;default:stop();break;}}if(i == SIZE){i = 0;memset(buffer,'\0',SIZE);}}if(TI);}

5.手机通过蓝牙控制小车_自定义按键

5.1手机通过蓝牙控制小车_自定义按键核心思路

  • 将蓝牙模块正确接线连接51单片机串口
  • 给51单片机,蓝牙模块上电,打开手机APP HC蓝牙助手进行连接
  • 通过自定义按钮使HC蓝牙助手发送相应控制小车指令

5.2将蓝牙模块正确接线连接51单片机串口

  相关接线请看我写的串口通信博文

5.3给51单片机,蓝牙模块上电,打开手机APP HC蓝牙助手进行连接

在这里插入图片描述
在这里插入图片描述

5.4通过自定义按钮使HC蓝牙助手发送相应控制小车指令

  1. 点击自定义按钮

在这里插入图片描述

  1. 点击设置方向按钮

在这里插入图片描述

  1. 在设置按钮名称处填写你需要设置的按钮名称,在设置按钮内容处填写你需要发送的指令,最后点击确认

在这里插入图片描述

  1. 依次设置完、五个指令后便可实现手机蓝牙控制小车。

6.蓝牙小车的点动控制

6.1蓝牙小车的点动控制核心思路

  • 主C文件主函数while(1)死循环中调用电机停止函数
  • 在串口中断函数中接收指令并执行调用电机相关函数时延时10毫秒实现点动
  • 通过串口助手自动发送模拟长按一直发送一直运行的状态。

  注:此工程由串口控制小车工程开发

6.2在主C文件主函数while(1)死循环中调用电机停止函数。

  • 函数调用代码
while(1)
{stop();
}
  • 主C文件代码
#include "motor.h"
#include "delay.h"
#include "uart.h"void main()
{UartInit();while(1){stop();}
}

6.3在串口中断函数中接收指令并执行调用电机相关函数时延时10毫秒实现点动

  • 延时10毫秒函数代码
void Delay10ms()		//@11.0592MHz
{unsigned char i, j;i = 18;j = 235;do{while (--j);} while (--i);
}
  • 在串口中断函数中调用代码
if(buffer[0]=='M')
{switch(buffer[1]){case '1':goFront();Delay10ms();break;case '2':goBack();Delay10ms();break;case '3':goLeft();Delay10ms();break;case '4':goRight();Delay10ms();break;default:stop();break;}}
  • 串口C文件代码
#include "reg52.h"
#include "motor.h"
#include "string.h"
#include "delay.h"#define SIZE 32sfr AUXR = 0x8e;   //声明AUXR寄存器地址
char buffer[SIZE];void UartInit()		//自己配
{//配置串口工作方式为方式1,从只收不发改为能收能发SCON =  0x50;//配置辅助寄存器,减少电磁辐射,稳定晶振频率  AUXR =  0x01;//设置定时器工作方式为定时器1的8位自动重装TMOD &= 0x0F;TMOD |= 0x20;//设置串口波特率为9600,0误差TH1   = 0xFD;TL1   = 0xFD;//打开定时器1TR1   = 1;//打开总中断EA = 1;//打开串口中断ES = 1;
}void UART_handler() interrupt 4
{//定义临时变量tmp用于判断接收的字符是否是需要的首字符。char tmp;//定义一个静态整型变量,在多次函数调用中只被执行一次初始化static int i = 0;//在串口中段函数中可以对发送接收中断标志进行处理if(RI == 1){RI = 0;     //必须软件置零tmp = SBUF;if(tmp=='M'){i = 0;}buffer[i++] = tmp;if(buffer[0]=='M'){switch(buffer[1]){case '1':goFront();Delay10ms();break;case '2':goBack();Delay10ms();break;case '3':goLeft();Delay10ms();break;case '4':goRight();Delay10ms();break;default:stop();break;}}if(i == SIZE){i = 0;memset(buffer,'\0',SIZE);}}if(TI);}

6.4通过串口助手自动发送模拟长按一直发送一直运行的状态。

  • 打开单片机下载器点击串口助手

在这里插入图片描述

  • 打开串口,写入指令M1,设置发送周期为1ms,点击自动发送。

在这里插入图片描述

  • 观察小车车轮,小车正在前行,说明模拟成功。

7.PWM软件调速

7.1 PWM软件调速核心思路

  • 打开感应开盖垃圾桶项目_舵机编程实战工程主C文件
  • 在工程内新建time0.c文件
  • 拷贝相关变量定时器0初始化函数定时器零中断函数
  • 修改定时器0中断函数,使之调用电机控制函数,实现调速
  • 建立time.h文件
  • 主C文件内每隔1.5秒改变速度变量,使小车电机变速

  注:此工程由蓝牙小车的点动控制工程开发

7.2打开感应开盖垃圾桶项目_舵机编程实战工程主C文件

在这里插入图片描述

7.3在工程内新建time0.c文件

在这里插入图片描述

7.4拷贝相关变量,定时器0初始化函数,定时器零中断函数

  • 拷贝相关变量代码
int cnt = 0;     //记录爆表次数
int angle;       //记录舵机角度变量

  修改angle为speed,也就是修改记录舵机角度变量为记录小车速度变量。把这两个变量类型修改为char型,节省空间

char cnt = 0;			//记录爆表次数
char speed = 0;  		 //调速变量
  • 拷贝定时器0初始化函数代码
void initTime0() //初始化定时器T0
{//1.设置定时器为T0,16位模式TMOD &= 0xF0;TMOD |= 0x01;//2.设置初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//3.启动定时器,开始计时TR0 = 1; //TR0为启动定时器标志,值为1启动定时器TF0 = 0;//4.打开定时器0的中断 赋1打开ET0 = 1;//5.打开总中断EA  赋1打开EA  = 1;
}
  • 拷贝定时器零中断函数
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{cnt++;//重新给定时器赋初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cnt < angle){sg90_con = 1;}else{sg90_con = 0;}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cnt == 20){cnt = 0;     //定时到20豪秒,cnt从0开始加sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平}
}

7.5修改定时器0中断函数,使之调用电机控制函数,实现调速

  • 把定时器零中断函数中第9行if(cnt < angle)修改为if(cnt < speed)
  • 把定时器零中断函数中第11行sg90_con = 1修改为goFront();
  • 把定时器零中断函数中第15行sg90_con = 0修改为stop();
  • 把定时器零中断函数中第21行sg90_con = 1;删除。
  • 添加motor.h头文件。
  • 修改后的函数代码
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{cnt++;//重新给定时器赋初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cnt < speed){//前进goFront();}else{//停止stop();}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cnt == 40){cnt = 0;     //定时到20豪秒,cnt从0开始加}
}
  • time0.c文件中的代码
#include "reg52.h"
#include "motor.h"
char cnt = 0;			//记录爆表次数
char speed = 0;   //调速变量void initTime0() //初始化定时器T0
{//1.设置定时器为T0,16位模式TMOD &= 0xF0;TMOD |= 0x01;//2.设置初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//3.启动定时器,开始计时TR0 = 1; //TR0为启动定时器标志,值为1启动定时器TF0 = 0;//4.打开定时器0的中断 赋1打开ET0 = 1;//5.打开总中断EA  赋1打开EA  = 1;
}void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{cnt++;//重新给定时器赋初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cnt < speed){//前进goFront();}else{//停止stop();}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cnt == 40){cnt = 0;     //定时到20豪秒,cnt从0开始加}
}

7.6建立time.h文件

  • 在time0.h中声明定时器0初始化函数
  • 代码体现
void initTime0();

7.7主C文件内每隔1.5秒改变速度变量,使小车电机变速

  • 在主函数中调用定时器0初始化函数
initTime0();
  • 在主C文件中运用extern关键字声明速度变量char speed。
extern char speed;
  • 在主函数while(1)死循环中每隔1.5秒改变速度变量的值。
while(1)
{speed = 10;Delay1500ms();speed = 15;Delay1500ms();speed = 20;Delay1500ms();speed = 25;Delay1500ms();speed = 30;Delay1500ms();speed = 35;Delay1500ms();speed = 40;Delay1500ms();
}
  • 在delay.c文件中建立延时1.5秒函数。
void Delay1500ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 11;j = 130;k = 111;do{do{while (--k);} while (--j);} while (--i);
}
  • 主C文件代码
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time0.h"extern char speed;void main()
{initTime0();UartInit();while(1){speed = 10;     //10为最小速度驱动,再小就无法运行Delay1500ms();speed = 15;Delay1500ms();speed = 20;Delay1500ms();speed = 25;Delay1500ms();speed = 30;Delay1500ms();speed = 35;Delay1500ms();speed = 40;Delay1500ms();}
}

7.8 PWM软件调速原理图

在这里插入图片描述

8.左右电机的各自调速管理

8.1左右电机的各自调速管理核心思路

  • motor.c文件内建立单独控制左右轮前进和停止函数,并在motor.h文件中声明。

  • 建立time1.ctime1.h文件用于对右轮的控制和初始化。

  • 修改time0.c左轮控制

  • 主C文件内每隔1.5秒改变左右轮速度变量,使小车左右轮电机差速运行

  注:此工程由PWM软件调速开发

8.2在motor.c文件内建立单独控制左右轮前进和停止函数,并在motor.h文件中声明。

  • 复制前进函数,修改名字为goFrontLeft()。删除右轮代码。
修改前
void goFront()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 1;
}修改后void goFrontLeft()
{LeftControA  = 0;LeftControB  = 1;
}

  按照以上步骤可以建立右轮控制函数

void goFrontRight()
{RightControA = 0;RightControB = 1;
}
  • 复制停止函数,修改名为stopLeft()。删除右轮代码
修改前
void stop()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 0;
}修改后
void stopLeft()
{LeftControA  = 0;LeftControB  = 0;
}

  按照以上步骤可以建立右轮停止函数函数

void stopRight()
{RightControA = 0;RightControB = 0;
}
  • 在motor.h中声明这四个函数
void goFrontLeft();void goFrontRight();void stopLeft();void stopRight();
  • motor.c文件中的代码
#include "reg52.h"sbit RightControA = P3^2;         //右轮控制A
sbit RightControB = P3^3;         //右轮控制B
sbit LeftControA  = P3^4;         //左轮控制A
sbit LeftControB  = P3^5;         //左轮控制Bvoid goLeft()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 0;
}void goRight()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 1;
}void goBack()
{RightControA = 1;RightControB = 0;LeftControA  = 1;LeftControB  = 0;
}void goFront()
{RightControA = 0;RightControB = 1;LeftControA  = 0;LeftControB  = 1;
}void stop()
{RightControA = 0;RightControB = 0;LeftControA  = 0;LeftControB  = 0;
}void goFrontLeft()
{LeftControA  = 0;LeftControB  = 1;
}void goFrontRight()
{RightControA = 0;RightControB = 1;
}void stopLeft()
{LeftControA  = 0;LeftControB  = 0;
}void stopRight()
{RightControA = 0;RightControB = 0;
}
  • motor.h文件中的代码

void goLeft();void goRight();void goBack();void goFront();void stop();void goFrontLeft();void goFrontRight();void stopLeft();void stopRight();

8.3建立time1.c和time1.h文件用于对右轮的控制和初始化。

  1. 拷贝time0.c文件代码到time1.c文件中
#include "reg52.h"
#include "motor.h"
char cnt = 0;			//记录爆表次数
char speed = 0;   //调速变量void initTime0() //初始化定时器T0
{//1.设置定时器为T0,16位模式TMOD &= 0xF0;TMOD |= 0x01;//2.设置初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//3.启动定时器,开始计时TR0 = 1; //TR0为启动定时器标志,值为1启动定时器TF0 = 0;//4.打开定时器0的中断 赋1打开ET0 = 1;//5.打开总中断EA  赋1打开EA  = 1;
}void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{cnt++;//重新给定时器赋初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cnt < speed){//前进goFront();}else{//停止stop();}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cnt == 40){cnt = 0;     //定时到20豪秒,cnt从0开始加}
}
  1. initTime0()修改为initTime1(),将所有的TH0TL0替换为TH1TL1。将TMOD的两个运算表达式后面的变量替换为0x0F0x01 << 4;实现使用定时器116位模式。将TR0TF0ET0修改为TR1TF1ET1
void initTime1() //初始化定时器T0
{//1.设置定时器为T0,16位模式TMOD &= 0x0F;TMOD |= 0x01 << 4;//2.设置初值,定时0.5毫秒TL1 = 0x33;TH1 = 0xFE;//3.启动定时器,开始计时TR1 = 1; //TR0为启动定时器标志,值为1启动定时器TF1 = 0;//4.打开定时器0的中断 赋1打开ET1 = 1;//5.打开总中断EA  赋1打开EA  = 1;
}
  1. Time0Handler() 修改为 Time1Handler()interrupt 1 修改为 interrupt 3cnt 修改为 cntRightspeed修改为speedRightgoFront();修改为goFrontRight();stop();修改为stopRight();
void Time1Handler() interrupt 3 //定时器T0中断函数,中断号为interrupt 1
{cntRight++;//重新给定时器赋初值,定时0.5毫秒TL1 = 0x33;TH1 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cntRight < speedRight){//前进goFrontRight();}else{//停止stopRight();}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cntRight == 40){cntRight = 0;     //定时到20豪秒,cnt从0开始加}
}
  1. 修改后的代码为
#include "reg52.h"
#include "motor.h"
char cntRight = 0;                            			//记录爆表次数
char speedRight = 0;   //调速变量void initTime1() //初始化定时器T0
{//1.设置定时器为T0,16位模式TMOD &= 0x0F;TMOD |= 0x01 << 4;//2.设置初值,定时0.5毫秒TL1 = 0x33;TH1 = 0xFE;//3.启动定时器,开始计时TR1 = 1; //TR0为启动定时器标志,值为1启动定时器TF1 = 0;//4.打开定时器0的中断 赋1打开ET1 = 1;//5.打开总中断EA  赋1打开EA  = 1;
}void Time1Handler() interrupt 3 //定时器T0中断函数,中断号为interrupt 1
{cntRight++;//重新给定时器赋初值,定时0.5毫秒TL1 = 0x33;TH1 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cntRight < speedRight){//前进goFrontRight();}else{//停止stopRight();}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cntRight == 40){cntRight = 0;     //定时到20豪秒,cnt从0开始加}
}

8.4修改time0.c为左轮控制

  1. cnt修改为cntLeftspeed修改为speedLeftgoFront();修改为goFrontLeft();stop();修改为stopLeft();
  2. 修改后的代码为
#include "reg52.h"
#include "motor.h"
char cntLeft = 0;			//记录爆表次数
char speedLeft = 0;   //调速变量void initTime0() //初始化定时器T0
{//1.设置定时器为T0,16位模式TMOD &= 0xF0;TMOD |= 0x01;//2.设置初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//3.启动定时器,开始计时TR0 = 1; //TR0为启动定时器标志,值为1启动定时器TF0 = 0;//4.打开定时器0的中断 赋1打开ET0 = 1;//5.打开总中断EA  赋1打开EA  = 1;
}void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{cntLeft ++;//重新给定时器赋初值,定时0.5毫秒TL0 = 0x33;TH0 = 0xFE;//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平if(cntLeft  < speedLeft){//前进goFrontLeft();}else{//停止stopLeft();}//判断cnt是否加到40,定时是否20毫秒PWM波形周期if(cntLeft  == 40){cntLeft  = 0;     //定时到20豪秒,cnt从0开始加}
}

8.5主C文件内每隔1.5秒改变左右轮速度变量,使小车左右轮电机差速运行

  1. 调速变量修改代码
while(1)
{speedRight = 40;speedLeft  = 40;Delay1500ms();speedRight = 10;     //10为最小速度驱动,再小就无法运行speedLeft  = 40;Delay1500ms();speedRight = 15;speedLeft  = 35;Delay1500ms();speedRight = 20;speedLeft  = 30;Delay1500ms();speedRight = 25;speedLeft  = 25;Delay1500ms();speedRight = 30;speedLeft  = 20;Delay1500ms();speedRight = 35;speedLeft  = 15;Delay1500ms();speedRight = 40;speedLeft  = 10;Delay1500ms();
}
  1. 主C文件代码
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time0.h"
#include "time1.h"extern char speedRight;
extern char speedLeft;void main()
{initTime0();initTime1();UartInit();while(1){speedRight = 40;speedLeft  = 40;Delay1500ms();speedRight = 10;     //10为最小速度驱动,再小就无法运行speedLeft  = 40;Delay1500ms();speedRight = 15;speedLeft  = 35;Delay1500ms();speedRight = 20;speedLeft  = 30;Delay1500ms();speedRight = 25;speedLeft  = 25;Delay1500ms();speedRight = 30;speedLeft  = 20;Delay1500ms();speedRight = 35;speedLeft  = 15;Delay1500ms();speedRight = 40;speedLeft  = 10;Delay1500ms();}
}

结束语

  很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/691361.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PostgreSQL按日期列创建分区表

在PostgreSQL中&#xff0c;实现自动创建分区表主要依赖于表的分区功能&#xff0c;这一功能从PostgreSQL 10开始引入。分区表可以帮助管理大量数据&#xff0c;通过分布数据到不同的分区来提高查询效率和数据维护的便捷性。以下是在PostgreSQL中自动创建分区表的一般步骤&…

【Git】Gitbash使用ssh 上传本地项目到github

SSH Git上传项目到GitHub&#xff08;图文&#xff09;_git ssh上传github-CSDN博客 前提 ssh-keygen -t rsa -C “自己的github电子邮箱” 生成密钥&#xff0c;公钥保存到自己的github的ssh里 1.先创建一个仓库&#xff0c;复制ssh地址 git init git add . git commit -m …

GEE必须会教程—跳舞的线(字符串类型)

字符串&#xff0c;GEE上跳舞的线&#xff01; GEE学习之路漫长&#xff0c;跟着小编一起走进今天的数据类型的学习。字符串是各大编程语言的常用数据类型&#xff0c;我们今天需要了解GEE平台上字符串的定义、以及常用的方法。 1.定义字符串 //字符串构造 var base_str &q…

「Java同步原理与底层实现解析」

原理概要&#xff1a; java虚拟机中的同步基于进入与结束Monitor对象实现&#xff0c;无论是显式同步&#xff08;同步代码块进入在jvm是根据monitorenter标志、结束是monitorexit标志&#xff0c;那最后一个是monitorexit是异常结束时被执行的释放指令&#xff09;、隐式同步…

STM32 输入捕获模式测频率

单片机学习&#xff01; 目录 文章目录 前言 一、输入捕获测频率配置步骤 二、代码示例及注意事项 2.1 RCC开启时钟 2.2 GPIO初始化 2.3 配置时基单元 2.4 配置输入捕获单元 2.5 选择从模式的触发源 2.6 配置从模式为Reset 2.7 开启定时器 总结 前言 博文介绍如何配置输入捕获电…

OpenAI 全新发布文生视频模型 Sora,支持 60s 超长长度,有哪些突破?将带来哪些影响?

Sora大模型简介 OpenAI 的官方解释了在视频数据基础上进行大规模训练生成模型的方法。 我们下面会摘取其中的关键部分罗列让大家快速get重点。 喜欢钻研的伙伴可以到官网查看技术报告&#xff1a; https://openai.com/research/video-generation-models-as-world-simulator…

AI破局俱乐部,你要了解的都在这里

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),代码实现篇

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

大模型量化技术原理-LLM.int8()、GPTQ

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;从而导致模型变得越来越大&#xff0c;因此&#xff0c;我们需要一些大模型压缩技术来降低模型部署的成本&#xff0c;并提升模型的推理性能。 模型压缩主要分…

不知如何获取1688工厂档案信息,你还在为此烦恼吗?

阿里巴巴集团旗下的B2B电子商务网站&#xff0c;提供海量优质商品&#xff0c;为采购商和供应商提供交流、合作、采购等服务&#xff0c;是很多没有货源优势的电商卖家首选的货源途径&#xff0c;也是国内最大、货源种类最齐全的货源网站。 不少做跨境电商无货源的朋友都想要1…

用html编写的招聘简历

用html编写的招聘简历 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</tit…

自定义异常处理演示

​ 为了防止黑客从前台异常信息&#xff0c;对系统进行攻击。同时&#xff0c;为了提高用户体验&#xff0c;我们都会都抛出的异常进行拦截处理。 一、全局异常处理 编写一个异常拦截类&#xff0c;如下&#xff1a;ControllerAdvice&#xff0c;很多初学者可能都没有听说过…

《最新出炉》系列初窥篇-Python+Playwright自动化测试-19-处理鼠标拖拽-中篇

1.简介 上一篇中&#xff0c;主要是介绍了拖拽的各种方法的理论知识以及实践&#xff0c;今天宏哥讲解和分享一下划取字段操作。例如&#xff1a;需要在一堆log字符中随机划取一段文字&#xff0c;然后右键选择摘取功能。 2.划取字段操作 划取字段操作就是在一段文字中随机选…

Linux系统——http协议介绍

目录 引言——Internet起源 一、http协议——超文本传输协议 1.http相关概念 2.访问浏览器的过程 3.http协议通信过程 4.http相关技术 4.1WEB开发语言 4.2html 4.3CSS 4.4JS 5.MIME——Multipurpose Internet Mail Extensions 多用途互联网邮件扩展 6.URI URN URL的…

【Redis,Java】Redis的两种序列化方式—nosql数据库

redis和mysql的区别&#xff1a; redis是属于nosql的数据库&#xff0c;而mysql是属于sql数据库&#xff0c;redis是属于nosql数据库。mysql是存储在磁盘中的&#xff0c;redis是存储在内存中的&#xff0c;所以redis的读取书读快。这里所说的redis代表nosql&#xff0c;而mysq…

【wails】(1):使用go做桌面应用开发,wails框架入门学习,在Linux上搭建环境,运行demo项目,并打包测试

1&#xff0c;视频地址 https://www.bilibili.com/video/BV1fK421b7QC/ 【wails】&#xff08;1&#xff09;&#xff1a;使用go做桌面应用开发&#xff0c;wails框架入门学习&#xff0c;在Linux上搭建环境&#xff0c;运行demo项目&#xff0c;并打包测试 2&#xff0c;参考…

在Ubuntu中使用python

目录 一、利用vim使用python 1、下载vim 2、使用vim创建python文件 3、编辑完成后的vim操作 4、如何运行 5、vim常见操作 二、安装Jupyter 1、更新系统 2、安装pip 注&#xff1a;pip无法应用的原因及解决方案 3、安装Jupyter 4、打开Jupyter 三、安装其他Python模…

ActiveMQ高可用架构涉及常用功能整理

ActiveMQ高可用架构涉及常用功能整理 1. activemq的集群模式2. 镜像模式高可用系统架构和相关组件2.1 架构说明2.2 相关概念说明2.3 消息模型2.3.1 点对点2.3.2 发布订阅 3. activemq常用命令4. activemq配置集群5. 疑问和思考5.1 activemq的数据删除策略是怎样的&#xff1f;5…

【软考问题】-- 1 - IT知识 - 信息化发展

一、基础问题 问题1:信息系统的生命周期可以简化为哪5个阶段? (1)系统规划(可行性分析与项目开发计划)(2)系统分析(需求分析) (3)系统设计(概要设计、 详细设计) (4)系统实施(编码、 测试) (5)系统运行和维护问题2:国家信息化体系六要素分别是什么? 1信息…

ChatGPT-用ChatGPT指令,自学任何领域的系统知识

1. 指令位置 Github仓库&#xff1a;Mr Ranedeer AI Tutor 但是需要开通chatgtp plus版本&#xff0c;并且打开代码解释器 2 使用 学习内容 开始学习 GPT甚至可以给你思考题&#xff0c;给出的答案还能进行评价 配置 通过配置表修改 深度 学习风格 沟通风格 语气风格 …