当前位置:   article > 正文

51单片机智能小车之测速小车原理和开发_智能小车测速模块原理

智能小车测速模块原理

目录

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

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

  1. //main.c
  2. #include "motor.h"
  3. #include "delay.h"
  4. #include "uart.h"
  5. #include "reg52.h"
  6. #include "time.h"
  7. #include "stdio.h"
  8. sbit speedIO = P3^2;//外部中断0
  9. unsigned int speedCnt = 0; //统计格子,脉冲次数
  10. extern unsigned int speed;//速度
  11. extern char signal; //主程序发速度数据的通知
  12. char speedMes[24]; //主程序发送速度数据的字符串缓冲区
  13. void Ex0Init()
  14. {
  15. EX0 = 1;//允许中断
  16. //EA = 1;在串口初始化函数中已经打开了总中断
  17. IT0 = 1;//外部中断的下降沿触发
  18. }
  19. void main()
  20. {
  21. Time0Init();//定时器0初始化
  22. UartInit();//串口相关初始化
  23. //外部中断初始化
  24. Ex0Init();
  25. while(1){
  26. if(signal){//定时器1s到点,把signal置一,主程序发送速度
  27. sprintf(speedMes,"speed:%d cm/s",speed);//串口数据的字符串拼装,speed是格子,每个格子1cm
  28. SendString(speedMes);//速度发出去
  29. signal = 0;//清0speed,下次由定时器1s后的中断处理中再置一
  30. }
  31. }
  32. }
  33. void speedHandler() interrupt 0 //外部中断处理函数
  34. {
  35. speedCnt++;//码盘转动了一个格子
  36. }
  37. //uart.c
  38. #include "reg52.h"
  39. #include "motor.h"
  40. #include "string.h"
  41. sbit D5 = P3^7;
  42. #define SIZE 12
  43. sfr AUXR = 0x8E;
  44. char buffer[SIZE];
  45. void UartInit(void) //9600bps@11.0592MHz
  46. {
  47. AUXR = 0x01;
  48. SCON = 0x50; //配置串口工作方式1,REN使能接收
  49. TMOD &= 0x0F;
  50. TMOD |= 0x20;//定时器1工作方式位8位自动重装
  51. TH1 = 0xFD;
  52. TL1 = 0xFD;//9600波特率的初值
  53. TR1 = 1;//启动定时器
  54. EA = 1;//开启总中断
  55. ES = 1;//开启串口中断
  56. }
  57. void SendByte(char mydata)
  58. {
  59. SBUF = mydata;
  60. while(!TI);
  61. TI = 0;
  62. }
  63. void SendString(char *str)
  64. {
  65. while(*str != '\0'){
  66. SendByte(*str);
  67. str++;
  68. }
  69. }
  70. //M1qian M2 hou M3 zuo M4 you
  71. void Uart_Handler() interrupt 4
  72. {
  73. static int i = 0;//静态变量,被初始化一次
  74. char tmp;
  75. if(RI)//中断处理函数中,对于接收中断的响应
  76. {
  77. RI = 0;//清除接收中断标志位
  78. tmp = SBUF;
  79. if(tmp == 'M'){
  80. i = 0;
  81. }
  82. buffer[i++] = tmp;
  83. //灯控指令
  84. if(buffer[0] == 'M'){
  85. switch(buffer[1]){
  86. case '1':
  87. goForward();
  88. break;
  89. case '2':
  90. goBack();
  91. break;
  92. case '3':
  93. goLeft();
  94. break;
  95. case '4':
  96. goRight();
  97. break;
  98. default:
  99. stop();
  100. break;
  101. }
  102. }
  103. if(i == 12) {
  104. memset(buffer, '\0', SIZE);
  105. i = 0;
  106. }
  107. }
  108. }
  109. //motor.c
  110. #include "reg52.h"
  111. sbit RightCon1A = P3^7;
  112. sbit RightCon1B = P3^3;
  113. sbit LeftCon1A = P3^4;
  114. sbit LeftCon1B = P3^5;
  115. void goForward()
  116. {
  117. LeftCon1A = 0;
  118. LeftCon1B = 1;
  119. RightCon1A = 0;
  120. RightCon1B = 1;
  121. }
  122. void goRight()
  123. {
  124. LeftCon1A = 0;
  125. LeftCon1B = 1;
  126. RightCon1A = 0;
  127. RightCon1B = 0;
  128. }
  129. void goLeft()
  130. {
  131. LeftCon1A = 0;
  132. LeftCon1B = 0;
  133. RightCon1A = 0;
  134. RightCon1B = 1;
  135. }
  136. void goBack()
  137. {
  138. LeftCon1A = 1;
  139. LeftCon1B = 0;
  140. RightCon1A = 1;
  141. RightCon1B = 0;
  142. }
  143. void stop()
  144. {
  145. LeftCon1A = 0;
  146. LeftCon1B = 0;
  147. RightCon1A = 0;
  148. RightCon1B = 0;
  149. }
  150. //time.c
  151. #include "motor.h"
  152. #include "reg52.h"
  153. extern unsigned int speedCnt;
  154. unsigned int speed;
  155. char signal = 0;
  156. unsigned int cnt = 0;
  157. void Time0Init()
  158. {
  159. //1. 配置定时器0工作模式位16位计时
  160. TMOD = 0x01;
  161. //2. 给初值,定一个0.5出来
  162. TL0=0x33;
  163. TH0=0xFE;
  164. //3. 开始计时
  165. TR0 = 1;
  166. TF0 = 0;
  167. //4. 打开定时器0中断
  168. ET0 = 1;
  169. //5. 打开总中断EA
  170. EA = 1;
  171. }
  172. void Time0Handler() interrupt 1
  173. {
  174. cnt++; //统计爆表的次数. cnt=1的时候,报表了1
  175. //重新给初值
  176. TL0=0x33;
  177. TH0=0xFE;
  178. if(cnt == 2000){//爆表2000次,经过了1s
  179. signal = 1;
  180. cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s
  181. //计算小车的速度,也就是拿到speedCnt的值
  182. speed = speedCnt;
  183. speedCnt = 0;//1秒后拿到speedCnt个格子,就能算出这1s的速度,格子清零
  184. }
  185. }

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 */

最终小车代码整合:

  1. //main.c
  2. #include "reg52.h"
  3. #include "intrins.h"
  4. #include "Oled.h"
  5. void main()
  6. {
  7. //1. OLED初始化
  8. Oled_Init();
  9. Oled_Clear();
  10. Oled_Show_Str(2,2,"speed:35cm/s");
  11. while(1);
  12. }
  13. //oled.c
  14. #include "reg52.h"
  15. #include "intrins.h"
  16. #include "Oledfont.h"
  17. sbit scl = P1^2;
  18. sbit sda = P1^3;
  19. void IIC_Start()
  20. {
  21. scl = 0;
  22. sda = 1;
  23. scl = 1;
  24. _nop_();
  25. sda = 0;
  26. _nop_();
  27. }
  28. void IIC_Stop()
  29. {
  30. scl = 0;
  31. sda = 0;
  32. scl = 1;
  33. _nop_();
  34. sda = 1;
  35. _nop_();
  36. }
  37. char IIC_ACK()
  38. {
  39. char flag;
  40. sda = 1;//就在时钟脉冲9期间释放数据线
  41. _nop_();
  42. scl = 1;
  43. _nop_();
  44. flag = sda;
  45. _nop_();
  46. scl = 0;
  47. _nop_();
  48. return flag;
  49. }
  50. void IIC_Send_Byte(char dataSend)
  51. {
  52. int i;
  53. for(i = 0;i<8;i++){
  54. scl = 0;//scl拉低,让sda做好数据准备
  55. sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
  56. _nop_();//发送数据建立时间
  57. scl = 1;//scl拉高开始发送
  58. _nop_();//数据发送时间
  59. scl = 0;//发送完毕拉低
  60. _nop_();//
  61. dataSend = dataSend << 1;
  62. }
  63. }
  64. void Oled_Write_Cmd(char dataCmd)
  65. {
  66. // 1. start()
  67. IIC_Start();
  68. //
  69. // 2. 写入从机地址 b0111 1000 0x78
  70. IIC_Send_Byte(0x78);
  71. // 3. ACK
  72. IIC_ACK();
  73. // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
  74. IIC_Send_Byte(0x00);
  75. // 5. ACK
  76. IIC_ACK();
  77. //6. 写入指令/数据
  78. IIC_Send_Byte(dataCmd);
  79. //7. ACK
  80. IIC_ACK();
  81. //8. STOP
  82. IIC_Stop();
  83. }
  84. void Oled_Write_Data(char dataData)
  85. {
  86. // 1. start()
  87. IIC_Start();
  88. //
  89. // 2. 写入从机地址 b0111 1000 0x78
  90. IIC_Send_Byte(0x78);
  91. // 3. ACK
  92. IIC_ACK();
  93. // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
  94. IIC_Send_Byte(0x40);
  95. // 5. ACK
  96. IIC_ACK();
  97. ///6. 写入指令/数据
  98. IIC_Send_Byte(dataData);
  99. //7. ACK
  100. IIC_ACK();
  101. //8. STOP
  102. IIC_Stop();
  103. }
  104. void Oled_Init(void){
  105. Oled_Write_Cmd(0xAE);//--display off
  106. Oled_Write_Cmd(0x00);//---set low column address
  107. Oled_Write_Cmd(0x10);//---set high column address
  108. Oled_Write_Cmd(0x40);//--set start line address
  109. Oled_Write_Cmd(0xB0);//--set page address
  110. Oled_Write_Cmd(0x81); // contract control
  111. Oled_Write_Cmd(0xFF);//--128
  112. Oled_Write_Cmd(0xA1);//set segment remap
  113. Oled_Write_Cmd(0xA6);//--normal / reverse
  114. Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
  115. Oled_Write_Cmd(0x3F);//--1/32 duty
  116. Oled_Write_Cmd(0xC8);//Com scan direction
  117. Oled_Write_Cmd(0xD3);//-set display offset
  118. Oled_Write_Cmd(0x00);//
  119. Oled_Write_Cmd(0xD5);//set osc division
  120. Oled_Write_Cmd(0x80);//
  121. Oled_Write_Cmd(0xD8);//set area color mode off
  122. Oled_Write_Cmd(0x05);//
  123. Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
  124. Oled_Write_Cmd(0xF1);//
  125. Oled_Write_Cmd(0xDA);//set com pin configuartion
  126. Oled_Write_Cmd(0x12);//
  127. Oled_Write_Cmd(0xDB);//set Vcomh
  128. Oled_Write_Cmd(0x30);//
  129. Oled_Write_Cmd(0x8D);//set charge pump enable
  130. Oled_Write_Cmd(0x14);//
  131. Oled_Write_Cmd(0xAF);//--turn on oled panel
  132. }
  133. void Oled_Clear()
  134. {
  135. unsigned char i,j; //-128 --- 127
  136. for(i=0;i<8;i++){
  137. Oled_Write_Cmd(0xB0 + i);//page0--page7
  138. //每个page从0列
  139. Oled_Write_Cmd(0x00);
  140. Oled_Write_Cmd(0x10);
  141. //0到127列,依次写入0,每写入数据,列地址自动偏移
  142. for(j = 0;j<128;j++){
  143. Oled_Write_Data(0);
  144. }
  145. }
  146. }
  147. void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
  148. unsigned int i;
  149. Oled_Write_Cmd(0xb0+(row*2-2)); //page 0
  150. Oled_Write_Cmd(0x00+(col&0x0f)); //low
  151. Oled_Write_Cmd(0x10+(col>>4)); //high
  152. for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
  153. Oled_Write_Data(F8X16[i]); //写数据oledTable1
  154. }
  155. Oled_Write_Cmd(0xb0+(row*2-1)); //page 1
  156. Oled_Write_Cmd(0x00+(col&0x0f)); //low
  157. Oled_Write_Cmd(0x10+(col>>4)); //high
  158. for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
  159. Oled_Write_Data(F8X16[i]); //写数据oledTable1
  160. }
  161. }
  162. /******************************************************************************/
  163. // 函数名称:Oled_Show_Char
  164. // 输入参数:oledChar
  165. // 输出参数:无
  166. // 函数功能:OLED显示单个字符
  167. /******************************************************************************/
  168. void Oled_Show_Str(char row,char col,char *str){
  169. while(*str!=0){
  170. Oled_Show_Char(row,col,*str);
  171. str++;
  172. col += 8;
  173. }
  174. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/767815
推荐阅读
相关标签
  

闽ICP备14008679号