智能小车之测速小车原理和开发

目录

1. 测速模块介绍

2. 测试原理和单位换算

3. 定时器和中断实现测速开发和调试代码

4. 小车速度显示在OLED屏


1. 测速模块介绍

  • 用途:广泛用于电机转速检测,脉冲计数,位置限位等。
  • 有遮挡,输出高电平;无遮挡,输出低电平
  • 接线 :VCC 接电源正极3.3-5V
  • GND 接电源负极 DO TTL开关信号输出
  • AO 此模块不起作用

2. 测试原理和单位换算

  • 轮子走一圈,经过一个周长,C = 2x3.14x半径= 3.14 x 直径(6.5cm)
  • 对应的码盘也转了一圈,码盘有20个格子,每经过一个格子,会遮挡(高电平)和不遮挡(低电平), 那么一个脉冲就是走了 3.14 * 6.5 cm /20 = 1.0205CM
  • 定时器可以设计成一秒,统计脉冲数,一个脉冲就是1cm
  • 假设一秒有80脉冲,那么就是80cm/s

3. 定时器和中断实现测速开发和调试代码

定时器介绍:

  • C51中的定时器和计数器是同一个硬件电路支持的,通过寄存器配置不同,就可以将他当做定时器 或者计数器使用。
  • 确切的说,定时器和计数器区别是致使他们背后的计数存储器加1的信号不同。当配置为定时器使 用时,每经过1个机器周期,计数存储器的值就加1。而当配置为计数器时,每来一个负跳变信号 (信号从P3.4 或者P3.5引脚输入),就加1,以此达到计数的目的。
  • 标准C51有2个定时器/计数器:T0和T1。他们的使用方法一致。C52相比C51多了一个T2

中断寄存器介绍:

CPU能响应定时器0中断的条件:需要配置IE寄存器的bit1: ET0 bit7:EA

  • 1. ET0中断允许要置一 ET0 = 1
  • 2. EA总中断要置一 EA = 1

测试数据通过串口发送到上位机

//main.c
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "reg52.h"
#include "time.h"
#include "stdio.h"sbit speedIO = P3^2;//外部中断0
unsigned int speedCnt = 0; //统计格子,脉冲次数
extern unsigned int speed;//速度
extern char signal; //主程序发速度数据的通知
char speedMes[24];  //主程序发送速度数据的字符串缓冲区void Ex0Init()
{EX0 = 1;//允许中断//EA = 1;在串口初始化函数中已经打开了总中断IT0 = 1;//外部中断的下降沿触发
}void main()
{Time0Init();//定时器0初始化UartInit();//串口相关初始化//外部中断初始化Ex0Init();while(1){if(signal){//定时器1s到点,把signal置一,主程序发送速度sprintf(speedMes,"speed:%d cm/s",speed);//串口数据的字符串拼装,speed是格子,每个格子1cmSendString(speedMes);//速度发出去signal = 0;//清0speed,下次由定时器1s后的中断处理中再置一}}
}void speedHandler() interrupt 0 //外部中断处理函数
{speedCnt++;//码盘转动了一个格子
}//uart.c
#include "reg52.h"
#include "motor.h"
#include "string.h"
sbit D5 = P3^7;
#define SIZE 12sfr AUXR = 0x8E;
char buffer[SIZE];void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定时器1工作方式位8位自动重装TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//启动定时器EA = 1;//开启总中断ES = 1;//开启串口中断
}void SendByte(char mydata)
{SBUF = mydata;while(!TI);TI = 0;
}void SendString(char *str)
{while(*str != '\0'){SendByte(*str);str++;}
}//M1qian  M2 hou M3 zuo  M4 you
void Uart_Handler() interrupt 4
{static int i = 0;//静态变量,被初始化一次char tmp;if(RI)//中断处理函数中,对于接收中断的响应{RI = 0;//清除接收中断标志位tmp = SBUF;if(tmp == 'M'){i = 0;}buffer[i++] = tmp;//灯控指令if(buffer[0] == 'M'){switch(buffer[1]){case '1':goForward();break;case '2':goBack();break;case '3':goLeft();break;case '4':goRight();break;default:stop();break;}}if(i == 12) {memset(buffer, '\0', SIZE);i = 0;}}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^7;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{LeftCon1A = 0;LeftCon1B = 1;RightCon1A = 0;RightCon1B = 1;
}void goRight()
{LeftCon1A = 0;LeftCon1B = 1;RightCon1A = 0;RightCon1B = 0;
}void goLeft()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 1;
}void goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//time.c
#include "motor.h"
#include "reg52.h"extern unsigned int speedCnt;
unsigned int speed;
char signal = 0;
unsigned int cnt = 0;void Time0Init()
{//1. 配置定时器0工作模式位16位计时TMOD = 0x01;//2. 给初值,定一个0.5出来TL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}void Time0Handler() interrupt 1
{cnt++;  //统计爆表的次数. cnt=1的时候,报表了1//重新给初值TL0=0x33;TH0=0xFE;if(cnt == 2000){//爆表2000次,经过了1ssignal = 1;cnt = 0;  //当100次表示1s,重新让cnt从0开始,计算下一次的1s//计算小车的速度,也就是拿到speedCnt的值speed = speedCnt;speedCnt = 0;//1秒后拿到speedCnt个格子,就能算出这1s的速度,格子清零}}

4. 小车速度显示在OLED屏

使用oled模块,oled写命令

写命令/数据的代码分析:

  • /* 1. start()
  • 2. 写入 b0111 1000 0x78
  • 3. ACK
  • 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
  • 5. ACK
  • 6. 写入指令/数据
  • 7. ACK
  • 8. STOP */

最终小车代码整合:

//main.c
#include "reg52.h"
#include "intrins.h"
#include "Oled.h"void main()
{//1. OLED初始化Oled_Init();Oled_Clear();Oled_Show_Str(2,2,"speed:35cm/s");while(1);
}//oled.c
#include "reg52.h"
#include "intrins.h"
#include "Oledfont.h"sbit scl = P1^2;
sbit sda = P1^3;void IIC_Start()
{scl = 0;sda = 1;scl = 1;_nop_();sda = 0;_nop_();
}void IIC_Stop()
{scl = 0;sda = 0;scl = 1;_nop_();sda = 1;_nop_();
}char IIC_ACK()
{char flag;sda = 1;//就在时钟脉冲9期间释放数据线_nop_();scl = 1;_nop_();flag = sda;_nop_();scl = 0;_nop_();return flag;
}void IIC_Send_Byte(char dataSend)
{int i;for(i = 0;i<8;i++){scl = 0;//scl拉低,让sda做好数据准备sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda_nop_();//发送数据建立时间scl = 1;//scl拉高开始发送_nop_();//数据发送时间scl = 0;//发送完毕拉低_nop_();//dataSend = dataSend << 1;}
}void Oled_Write_Cmd(char dataCmd)
{//	1. start()IIC_Start();//		//	2. 写入从机地址  b0111 1000 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 写入命令   (0)(1)000000写入数据IIC_Send_Byte(0x00);//	5. ACKIIC_ACK();//6. 写入指令/数据IIC_Send_Byte(dataCmd);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Write_Data(char dataData)
{//	1. start()IIC_Start();//		//	2. 写入从机地址  b0111 1000 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 写入命令   (0)(1)000000写入数据IIC_Send_Byte(0x40);//	5. ACKIIC_ACK();///6. 写入指令/数据IIC_Send_Byte(dataData);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line address  Oled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128   Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel		
}void Oled_Clear()
{unsigned char i,j; //-128 --- 127for(i=0;i<8;i++){Oled_Write_Cmd(0xB0 + i);//page0--page7//每个page从0列Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);//0到127列,依次写入0,每写入数据,列地址自动偏移for(j = 0;j<128;j++){Oled_Write_Data(0);}}
}void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2unsigned int  i;Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //high	for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){Oled_Write_Data(F8X16[i]);                            //写数据oledTable1}Oled_Write_Cmd(0xb0+(row*2-1));                           //page 1Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //highfor(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){Oled_Write_Data(F8X16[i]);                            //写数据oledTable1}		
}/******************************************************************************/
// 函数名称:Oled_Show_Char 
// 输入参数:oledChar 
// 输出参数:无 
// 函数功能:OLED显示单个字符
/******************************************************************************/
void Oled_Show_Str(char row,char col,char *str){while(*str!=0){Oled_Show_Char(row,col,*str);str++;col += 8;	}		
}

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

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

相关文章

算法通过村第六关-树青铜笔记|中序后序

文章目录 前言1. 树的常见概念2. 树的性质3. 树的定义与存储方式4. 树的遍历方式5. 通过序列构建二叉树5.1 前中序列恢复二叉树5.2 中后序列恢复二叉树 总结 前言 提示&#xff1a;瑞秋是个小甜心&#xff0c;她只喜欢被爱&#xff0c;不懂的去爱人。 --几米《你们 我们 他们》…

基础算法--理解递归

理解递归 递归的两个特点 调用自身结束条件 举个从小就听过的例子&#xff1a; 1. 从前有座山&#xff0c;山中有座庙&#xff0c;庙里有个老和尚&#xff0c;老和尚在给小和尚讲故事&#xff1a;2. 从前有座山&#xff0c;山中有座庙&#xff0c;庙里有个老和尚&#xff0c;…

JAVA实现SAP接口

JAVA实现SAP接口 环境spring-bootmaven 1.maven依赖 <dependency><groupId>com.github.virtualcry</groupId><artifactId>sapjco-spring-boot-starter</artifactId><version>3.1.4</version></dependency>2.配置文件 applic…

假期摆烂之学习javaweb

Mybatis: 概念&#xff1a; 是一款优秀的持久层框架&#xff0c;用于简化 JDBC的开发&#xff1a;持久层也就是三层架构里面的dao层&#xff0c;JDBC是规范&#xff1b;框架就是一个半成品的软件&#xff0c;是一套可重复用&#xff0c;通用的&#xff0c;软件基础代码模型&a…

文章预览 安防监控/视频存储/视频汇聚平台EasyCVR播放优化小tips

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;可实现视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、H.265自动转码H.264、平台级联等。为了便于用户二次开发、调用与集成&#xff0c;…

Vue3入门

Vu3 更多的优势 更容易维护(组合式API;更好的支持TypeScript支持)更快的速度(重写diff算法;模板编译优化;更高效的组件初始化)更小的体积(良好的TreeShaking;按需引入)更优的数据响应式(Proxy主要是为了处理动态添加的对象属性不是响应式的问题)vue3官方文档:简介…

sql:SQL优化知识点记录(十五)

&#xff08;1&#xff09;MySQL主从复制 我们这里配置一Windows上的MySql做主机&#xff0c;Linux上的MySql做从机&#xff0c;搭建一主一从 测试以下是否能够拼通&#xff1a;从Linux上&#xff1a;167&#xff0c;连接Windows的165 从Windows的165 连接Linux上&#xff1a;…

2023--9-8 高斯消元解线性方程组

题目链接&#xff1a;高斯消元解线性方程组 #include <iostream> #include <algorithm> #include <cmath>using namespace std;const int N 110; const double eps 1e-8;int n; double a[N][N];int gauss() {int c, r;for(c 0, r 0; c < n; c){// 找到…

基于Java+SpringBoot+Vue前后端分离火锅店管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

003微信小程序云开发API数据库-新增集合-删除集合-获取集合信息

文章目录 1.微信小程序云开发API数据库-新增集合案例代码 2.微信小程序云开发API数据库-删除集合案例代码 3.微信小程序云开发API数据库-获取集合信息案例代码 1.微信小程序云开发API数据库-新增集合 微信小程序云开发API数据库是一个方便快捷的数据库解决方案&#xff0c;可以…

【Kafka系列】(一)Kafka入门

有的时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 系列文章地址 Kafka是什么&#xff1f; 一句话概括&#xff1a;「Apache Kafka 是一款开源的消息引擎系统」 什么是消息引擎系统&#…

JVM 对象的访问方式

对象访问的方式 Java程序会通过栈上的reference数据来操作堆上的具体对象。 句柄法 Java堆中将可能会划分出一块内存来作为句柄池&#xff0c;reference中存储的就是对象的句柄地址&#xff0c;而句柄中包含了对象实例数据与类型数据各自具体的地址信息。移动的时候不…

进阶C语言-指针的进阶(上)

指针的进阶 &#x1f4d6;1.字符指针&#x1f4d6;2.指针数组&#x1f4d6;3.数组指针&#x1f388;3.1 数组指针的定义&#x1f388;3.2 &数组名VS数组名&#x1f388;3.3 数组指针的使用 &#x1f4d6;4.数组参数、指针参数&#x1f388;4.1一维数组传参&#x1f388;4.2…

VSCode下载、安装及配置、调试的一些过程理解

第一步先下载了vscode&#xff0c;官方地址为&#xff1a;https://code.visualstudio.com/Download 第二步安装vscode&#xff0c;安装环境是win10&#xff0c;安装基本上就是一步步默认即可。 第三步汉化vscode&#xff0c;这一步就是去扩展插件里面下载一个中文插件即可&am…

C++动态内存管理+模板

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; C&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大…

Web3.0:重新定义互联网的未来

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Web3.0&#xff1a;重新定义互联网的未来 Web3.0是指下一代互联网&#xff0c;也称为“分布式互联网”。相比于Web1.0和Web2.0&#xff0c;Web3.0具有更强的去中心化、…

常见的图像格式介绍:RAW、RGB、YUV

常见的图像格式有RAW、RGB、YUV这三大类 1. RAW raw图像指的是sensor输出的原始数据&#xff0c;常见的有8位、10位、12位之分&#xff0c;分别表示一个像素点所占的字节数为8bit、10bit、12bit。 raw数据常见的有四种Bayer模式&#xff1a;GRBG、RGGB、BGGR&#xff08;下图…

【力扣每日一题】2023.9.9 课程表

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一些课程的先修关系&#xff0c;也就是有些课我们需要先去学其他的课程才能学习&#xff0c;问我们是否可以学习完所有的课程。…

浅谈能源汽车下乡充电桩建设优化建议及解决方案

1.趋势分析 新能源汽车下乡已经成为提振汽车市场表现、推动汽车行业发展的重要措施。国家发改委日前也提出&#xff0c;汽车消费是支撑消费的“大头”&#xff0c;将加快推进充电桩和城市停车设施建设&#xff0c;大力推动新能源汽车下乡&#xff0c;鼓励汽车企业开发更适宜县…

算法与设计分析--实验一

蛮力算法的设计与分析&#xff08;暴力&#xff09; 这次是某不知名学院开学课程的第一次实验&#xff0c;一共5道题&#xff0c;来自力扣 第一题.216组合总和*力扣题目链接 第一道题是经典的树型回溯 class Solution { public:vector<vector<int>> combinatio…