1.电机模块开发
L9110s概述
接通VCC,GND 模块电源指示灯亮, 以下资料来源官方,具体根据实际调试
IA1输入高电平,IA1输入低电平,【OA1 OB1】电机正转;
IA1输入低电平,IA1输入高电平,【OA1 OB1】电机反转;
IA2输入高电平,IA2输入低电平,【OA2 OB2】电机正转;
IA2输入低电平,IA2输入高电平,【OA2 OB2】电机反转;
1.1 让小车动起来
核心代码:
#include "reg52.h" #include "intrins.h" sbit RightCon1A = P3^2; sbit RightCon1B = P3^3; sbit LeftCon1A = P3^4; sbit LeftCon1B = P3^5; void Delay1000ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); } void goForward() { LeftCon1A = 0; LeftCon1B = 1; RightCon1A = 0; RightCon1B = 1; } void goLeft() { LeftCon1A = 0; LeftCon1B = 0; RightCon1A = 0; RightCon1B = 1; } void goRight() { LeftCon1A = 0; LeftCon1B = 1; RightCon1A = 0; RightCon1B = 0; } void goBack() { LeftCon1A = 1; LeftCon1B = 0; RightCon1A = 1; RightCon1B = 0; } void main() { while(1){ goForward(); Delay1000ms(); Delay1000ms(); goBack(); Delay1000ms(); Delay1000ms(); goLeft(); Delay1000ms(); Delay1000ms(); goRight(); Delay1000ms(); Delay1000ms(); } }
1.2 串口控制小车方向
- 串口分文件编程进行代码整合——通过现象来改代码
- 接入蓝牙模块,通过蓝牙控制小车
- 添加点动控制,如果APP支持按下一直发数据,松开就停止发数据(蓝牙调试助手的自定义按键不 能实现),就能实现前进按键按下后小车一直往前走的功能
1.3 如何进行小车PWM调速
原理: 全速前进是LeftCon1A = 0; LeftCon1B = 1;完全停止是LeftCon1A = 0;LeftCon1B = 0;那么单位时 间内,比如20ms, 有15ms是全速前进,5ms是完全停止, 速度就会比5ms全速前进,15ms完全停止获得的功率多,相应的速度更快!
开发:借用PWM的舵机控制代码
核心代码:
#include "motor.h" #include "delay.h" #include "uart.h" #include "time.h" extern char speed; void main() { Time0Init(); //UartInit(); while(1){ speed = 10;//10份单位时间全速运行,30份停止,所以慢,20ms是40份的500us Delay1000ms(); Delay1000ms(); speed = 20; Delay1000ms(); Delay1000ms(); speed = 40; Delay1000ms(); Delay1000ms(); } } //time.c #include "motor.h" #include "reg52.h" char speed; char 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. 打开总中断EA EA = 1; } void Time0Handler() interrupt 1 { cnt++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL0=0x33; TH0=0xFE; //控制PWM波 if(cnt < speed){ //前进 goForward(); }else{ //停止 stop(); } if(cnt == 40){//爆表40次,经过了20ms cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s } }
1.4 PWM方式实现小车转向
原理: 左轮定时器0调速,右轮定时器1调速,那么左转就是右轮速度大于左轮!
核心代码:
#include "motor.h" #include "reg52.h" char speedLeft; char cntLeft = 0; char speedRight; char cntRight = 0; void Time1Init() { //1. 配置定时器1工作模式位16位计时 TMOD &= 0x0F; TMOD |= 0x1 << 4; //2. 给初值,定一个0.5出来 TL1=0x33; TH1=0xFE; //3. 开始计时 TR1 = 1; TF1 = 0; //4. 打开定时器1中断 ET1 = 1; //5. 打开总中断EA EA = 1; } void Time0Init() { //1. 配置定时器0工作模式位16位计时 TMOD = 0x01; //2. 给初值,定一个0.5出来 TL0=0x33; TH0=0xFE; //3. 开始计时 TR0 = 1; TF0 = 0; //4. 打开定时器0中断 ET0 = 1; //5. 打开总中断EA EA = 1; } void Time1Handler() interrupt 3 { cntRight++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL1=0x33; TH1=0xFE; //控制PWM波 if(cntRight < speedRight){ //右前进 goForwardRight(); }else{ //停止 stopRight(); } if(cntRight == 40){//爆表40次,经过了20ms cntRight = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s } } void Time0Handler() interrupt 1 { cntLeft++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL0=0x33; TH0=0xFE; //控制PWM波 if(cntLeft < speedLeft){ //左前进 goForwardLeft(); }else{ //停止 stopLeft(); } if(cntLeft == 40){//爆表40次,经过了20ms cntLeft = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s } }
2.循迹小车
2.1 循迹模块使用
- TCRT5000传感器的红外发射二极管不断发射红外线
- 当发射出的红外线没有被反射回来或被反射回来但强度不够大时
- 红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态
- 被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和
- 此时模块的输出端为低电平,指示二极管被点亮
- 总结就是一句话,没反射回来,D0输出高电平,灭灯
接线方式
- VCC:接电源正极(3-5V)
- GND:接电源负极 DO:TTL开关信号输出0、1
- AO:模拟信号输出(不同距离输出不同的电压,此脚一般可以不接)
2.2 循迹小车原理
由于黑色具有较强的吸收能力,当循迹模块发射的红外线照射到黑线时,红外线将会被黑线吸收,导致 循迹模块上光敏三极管处于关闭状态,此时模块上一个LED熄灭。在没有检测到黑线时,模块上两个LED常亮
总结就是一句话,有感应到黑线,D0输出高电平 ,灭灯
2.3 循迹小车核心代码
//main.c #include "motor.h" #include "delay.h" #include "uart.h" #include "time.h" #include "reg52.h" extern char speedLeft; extern char speedRight; sbit leftSensor = P2^7; sbit rightSensor = P2^6; void main() { Time0Init(); Time1Init(); //UartInit(); while(1){ if(leftSensor == 0 && rightSensor == 0){ speedLeft = 32; speedRight = 40; } if(leftSensor == 1 && rightSensor == 0){ speedLeft = 12;//10份单位时间全速运行,30份停止,所以慢,20ms是40份的500us speedRight = 40; } if(leftSensor == 0 && rightSensor == 1){ speedLeft = 32; speedRight = 20; } if(leftSensor == 1 && rightSensor == 1){ //停 speedLeft = 0; speedRight = 0; } } } //motor.c #include "reg52.h" sbit RightCon1A = P3^2; sbit RightCon1B = P3^3; sbit LeftCon1A = P3^4; sbit LeftCon1B = P3^5; void goForwardLeft() { LeftCon1A = 0; LeftCon1B = 1; } void stopLeft() { LeftCon1A = 0; LeftCon1B = 0; } void goForwardRight() { RightCon1A = 0; RightCon1B = 1; } void stopRight() { RightCon1A = 0; RightCon1B = 0; } 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; } //delay.c #include "intrins.h" void Delay1000ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); } //time.c #include "motor.h" #include "reg52.h" char speedLeft; char cntLeft = 0; char speedRight; char cntRight = 0; void Time1Init() { //1. 配置定时器1工作模式位16位计时 TMOD &= 0x0F; TMOD |= 0x1 << 4; //2. 给初值,定一个0.5出来 TL1=0x33; TH1=0xFE; //3. 开始计时 TR1 = 1; TF1 = 0; //4. 打开定时器1中断 ET1 = 1; //5. 打开总中断EA EA = 1; } void Time0Init() { //1. 配置定时器0工作模式位16位计时 TMOD = 0x01; //2. 给初值,定一个0.5出来 TL0=0x33; TH0=0xFE; //3. 开始计时 TR0 = 1; TF0 = 0; //4. 打开定时器0中断 ET0 = 1; //5. 打开总中断EA EA = 1; } void Time1Handler() interrupt 3 { cntRight++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL1=0x33; TH1=0xFE; //控制PWM波 if(cntRight < speedRight){ //右前进 goForwardRight(); }else{ //停止 stopRight(); } if(cntRight == 40){//爆表40次,经过了20ms cntRight = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s } } void Time0Handler() interrupt 1 { cntLeft++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL0=0x33; TH0=0xFE; //控制PWM波 if(cntLeft < speedLeft){ //左前进 goForwardLeft(); }else{ //停止 stopLeft(); } if(cntLeft == 40){//爆表40次,经过了20ms cntLeft = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s } }
3.跟随/避障小车
3.1 红外壁障模块分析
原理和循迹是一样的,循迹红外观朝下,跟随朝前
3.2 跟随小车的原理
- 左边跟随模块能返回红外,输出低电平,右边不能返回,输出高电平,说明物体在左边,需要左转
- 右边跟随模块能返回红外,输出低电平,左边不能返回,输出高电平,说明物体在右边,需要右转
3.3 跟随小车开发和调试代码
//main.c #include "motor.h" #include "delay.h" #include "reg52.h" //sbit leftSensor = P2^7; //sbit rightSensor = P2^6; sbit leftSensor = P2^5; sbit rightSensor = P2^4; void main() { while(1){ if(leftSensor == 0 && rightSensor == 0){ goForward(); } if(leftSensor == 1 && rightSensor == 0){ goRight(); } if(leftSensor == 0 && rightSensor == 1){ goLeft(); } if(leftSensor == 1 && rightSensor == 1){ //停 stop(); } } } //motor.c #include "reg52.h" sbit RightCon1A = P3^2; 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; } //delay.c #include "intrins.h" void Delay1000ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); }
3.4 超声波模块介绍
使用超声波模块,型号:HC-SR04
- 怎么让它发送波 Trig ,给Trig端口至少10us的高电平
- 怎么知道它开始发了 Echo信号,由低电平跳转到高电平,表示开始发送波
- 怎么知道接收了返回波 Echo,由高电平跳转回低电平,表示波回来了
- 怎么算时间 Echo引脚维持高电平的时间! 波发出去的那一下,开始启动定时器 波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
- 怎么算距离 距离 = 速度 (340m/s)* 时间/2
时序图:
3.5 摇头测距小车开发和调试代码
//main.c #include "reg52.h" #include "hc04.h" #include "delay.h" #include "sg90.h" #include "motor.h" #define MIDDLE 0 #define LEFT 1 #define RIGHT 2 void main() { char dir; double disMiddle; double disLeft; double disRight; Time0Init(); Time1Init(); //舵机的初始位置 sgMiddle(); Delay300ms(); Delay300ms(); dir = MIDDLE; while(1){ if(dir != MIDDLE){ sgMiddle(); dir = MIDDLE; Delay300ms(); } disMiddle = get_distance(); if(disMiddle > 35){ //前进 goForward(); }else if(disMiddle < 10){ goBack(); }else { //停止 stop(); //测左边距离 sgLeft(); Delay300ms(); disLeft = get_distance(); sgMiddle(); Delay300ms(); sgRight(); dir = RIGHT; Delay300ms(); disRight = get_distance(); if(disLeft < disRight){ goRight(); Delay150ms(); stop(); } if(disRight < disLeft){ goLeft(); Delay150ms(); stop(); } } } } //hc04.c #include "reg52.h" #include "delay.h" sbit Trig = P2^3; sbit Echo = P2^2; void Time1Init() { TMOD &= 0x0F; //设置定时器模式 TMOD |= 0x10; TH1 = 0; TL1 = 0; //设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器 } void startHC() { Trig = 0; Trig = 1; Delay10us(); Trig = 0; } double get_distance() { double time; //定时器数据清零,以便下一次测距 TH1 = 0; TL1 = 0; //1. Trig ,给Trig端口至少10us的高电平 startHC(); //2. echo由低电平跳转到高电平,表示开始发送波 while(Echo == 0); //波发出去的那一下,开始启动定时器 TR1 = 1; //3. 由高电平跳转回低电平,表示波回来了 while(Echo == 1); //波回来的那一下,我们开始停止定时器 TR1 = 0; //4. 计算出中间经过多少时间 time = (TH1 * 256 + TL1)*1.085;//us为单位 //5. 距离 = 速度 (340m/s)* 时间/2 return (time * 0.017); } //delay.c #include "intrins.h" void Delay2000ms() //@11.0592MHz { unsigned char i, j, k; i = 15; j = 2; k = 235; do { do { while (--k); } while (--j); } while (--i); } void Delay10us() //@11.0592MHz { unsigned char i; i = 2; while (--i); } void Delay300ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 3; j = 26; k = 223; do { do { while (--k); } while (--j); } while (--i); } void Delay150ms() //@11.0592MHz { unsigned char i, j, k; i = 2; j = 13; k = 237; do { do { while (--k); } while (--j); } while (--i); } void Delay450ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 4; j = 39; k = 209; do { do { while (--k); } while (--j); } while (--i); } //sg90.c #include "reg52.h" #include "delay.h" sbit sg90_con = P1^1; int jd; int cnt = 0; void Time0Init() { //1. 配置定时器0工作模式位16位计时 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //2. 给初值,定一个0.5出来 TL0=0x33; TH0=0xFE; //3. 开始计时 TR0 = 1; TF0 = 0; //4. 打开定时器0中断 ET0 = 1; //5. 打开总中断EA EA = 1; } void sgMiddle() { //中间位置 jd = 3; //90度 1.5ms高电平 cnt = 0; } void sgLeft() { //左边位置 jd = 5; //135度 1.5ms高电平 cnt = 0; } void sgRight() { //右边位置 jd = 1; //0度 cnt = 0; } void Time0Handler() interrupt 1 { cnt++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL0=0x33; TH0=0xFE; //控制PWM波 if(cnt < jd){ sg90_con = 1; }else{ sg90_con = 0; } if(cnt == 40){//爆表40次,经过了20ms cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s sg90_con = 1; } } //motor.c #include "reg52.h" sbit RightCon1A = P3^2; 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; }
4.测速小车
4.1 测速模块
- 用途:广泛用于电机转速检测,脉冲计数,位置限位等。
- 有遮挡,输出高电平;无遮挡,输出低电平
- 接线 :VCC 接电源正极3.3-5V
- GND 接电源负极 DO TTL开关信号输出
- AO 此模块不起作用
4.2 测试原理和单位换算
- 轮子走一圈,经过一个周长,C = 2x3.14x半径= 3.14 x 直径(6.5cm)
- 对应的码盘也转了一圈,码盘有20个格子,每经过一个格子,会遮挡(高电平)和不遮挡(低电平), 那么一个脉冲就是走了 3.14 * 6.5 cm /20 = 1.0205CM
- 定时器可以设计成一秒,统计脉冲数,一个脉冲就是1cm
- 假设一秒有80脉冲,那么就是80cm/s
4.3 定时器和中断实现测速开发和调试代码
测试数据通过串口发送到上位机
//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是格子,每个格子1cm SendString(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 12 sfr 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. 打开总中断EA EA = 1; } void Time0Handler() interrupt 1 { cnt++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值 TL0=0x33; TH0=0xFE; if(cnt == 2000){//爆表2000次,经过了1s signal = 1; cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s //计算小车的速度,也就是拿到speedCnt的值 speed = speedCnt; speedCnt = 0;//1秒后拿到speedCnt个格子,就能算出这1s的速度,格子清零 } }
4.4 小车速度显示在OLED屏
使用oled模块
//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 0x78 IIC_Send_Byte(0x78); // 3. ACK IIC_ACK(); // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据 IIC_Send_Byte(0x00); // 5. ACK IIC_ACK(); //6. 写入指令/数据 IIC_Send_Byte(dataCmd); //7. ACK IIC_ACK(); //8. STOP IIC_Stop(); } void Oled_Write_Data(char dataData) { // 1. start() IIC_Start(); // // 2. 写入从机地址 b0111 1000 0x78 IIC_Send_Byte(0x78); // 3. ACK IIC_ACK(); // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据 IIC_Send_Byte(0x40); // 5. ACK IIC_ACK(); ///6. 写入指令/数据 IIC_Send_Byte(dataData); //7. ACK IIC_ACK(); //8. STOP IIC_Stop(); } void Oled_Init(void){ Oled_Write_Cmd(0xAE);//--display off Oled_Write_Cmd(0x00);//---set low column address Oled_Write_Cmd(0x10);//---set high column address Oled_Write_Cmd(0x40);//--set start line address Oled_Write_Cmd(0xB0);//--set page address Oled_Write_Cmd(0x81); // contract control Oled_Write_Cmd(0xFF);//--128 Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverse Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64) Oled_Write_Cmd(0x3F);//--1/32 duty Oled_Write_Cmd(0xC8);//Com scan direction Oled_Write_Cmd(0xD3);//-set display offset Oled_Write_Cmd(0x00);// Oled_Write_Cmd(0xD5);//set osc division Oled_Write_Cmd(0x80);// Oled_Write_Cmd(0xD8);//set area color mode off Oled_Write_Cmd(0x05);// Oled_Write_Cmd(0xD9);//Set Pre-Charge Period Oled_Write_Cmd(0xF1);// Oled_Write_Cmd(0xDA);//set com pin configuartion Oled_Write_Cmd(0x12);// Oled_Write_Cmd(0xDB);//set Vcomh Oled_Write_Cmd(0x30);// Oled_Write_Cmd(0x8D);//set charge pump enable Oled_Write_Cmd(0x14);// Oled_Write_Cmd(0xAF);//--turn on oled panel } void Oled_Clear() { unsigned char i,j; //-128 --- 127 for(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-2 unsigned int i; Oled_Write_Cmd(0xb0+(row*2-2)); //page 0 Oled_Write_Cmd(0x00+(col&0x0f)); //low Oled_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 1 Oled_Write_Cmd(0x00+(col&0x0f)); //low Oled_Write_Cmd(0x10+(col>>4)); //high for(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; } }
51单片机智能小车(循迹、跟随、避障、测速、蓝牙、wifie、4g、语音识别)总结-2