嵌入式学习之路2
-
- Day31(2025-12.21--2024-10.25)
- Day32(2025-12.23--2024-10.28)
-
- [第 21 章 18B20](#第 21 章 18B20)
- [第 22 章 DS1302 实时时钟](#第 22 章 DS1302 实时时钟)
- [第 23 章关于通信协议的总结](#第 23 章关于通信协议的总结)
- 51智能车
-
- Day33(2025-12.24--2024-10.29)
-
- [第 1 章 架构设计](#第 1 章 架构设计)
- [第 2 章 避障](#第 2 章 避障)
-
- [2.1 基础准备](#2.1 基础准备)
- [2.2 测距模块](#2.2 测距模块)
- [2.3 电机模块](#2.3 电机模块)
- [2.4 应用层](#2.4 应用层)
- [3 遥控](#3 遥控)
-
- [3.1 蓝牙模块](#3.1 蓝牙模块)
- [3.2 应用层](#3.2 应用层)
- [第 4 章 巡线](#第 4 章 巡线)
-
- [4.1 光电反射传感器模块](#4.1 光电反射传感器模块)
- [4.2 应用层](#4.2 应用层)
- [第 5 章 模式切换](#第 5 章 模式切换)
-
- [5.1 独立按键](#5.1 独立按键)
- [5,2 模式切换](#5,2 模式切换)
Day31(2025-12.21--2024-10.25)
第 20 章 OLED
20.1 SSD1315驱动芯片

① 组成
| 介绍 | |
|---|---|
| MCU Interface | 单片机接口 |
| Command Decoder | 命令解码器 |
| Graphic Display Data RAM | GDDRAM,图形显示数据内存 |
| Common Driver | 公共驱动,连接OLED的行,共64个引脚 |
| Segment Driver | 段驱动,连接OLED的列,共128个引脚 |
② I²C 总线协议
设备地址: 011110 + SA0 SA0默认是0
7bit地址+写标志(0) : 0x78
数据字节和控制字节:
数据字节 命令 显示数据
控制字节
== ③ GDDRAM==





内部结构:分为8个Page,每个Page 128 个Byte
寻址方式:
- 页寻址
- 水平寻址
- 垂直寻址
内存每个bit与屏幕像素的映射
影响因素: GDDRAM和SSD1315输出引脚之间(可以配置)
SSD1315输出引脚与屏幕之间
通过时序信号我们可以看出如何来写入数据或者读出数据


20.2 使用IIC协议驱动SSD1315芯片控制OLED显示字符串和数字
Com
c
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__
#include <STC89C5xRC.H>
#include <INTRINS.H>
// 类型别名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/**
* @brief 延时函数,指定延时多少毫秒
*
* @param count 指定多少毫秒
*/
void Delayms(u16 count);
#endif
c
/*******************************************************************************
****文件路径 : \使用定时器中断控制LED实现流水灯效果\src\Com\Com_Util.c
****作者名称 : error: git config user.name & please set dead value or install git
****文件版本 : V1.0.0
****创建日期 : 2025-12-15 22:34:16
****简要说明 :
****
****版权信息 : 2025 by ${git_name}, All Rights Reserved.
********************************************************************************/
#include "Com_Util.h"
// 延时函数,指定延时多少毫秒
/*******************************************************************************
****函数功能:
****入口参数: count:
****出口参数:
****函数备注:
********************************************************************************/
void Delayms(u16 count)
{
u8 data i, j;
while (count)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j)
;
} while (--i);
count--;
}
}
Dri
Dri_IIC
c
#ifndef __DRI_IIC_H__
#define __DRI_IIC_H__
#include "Com_Util.h"
#define SCL P17
#define SDA P16
/**
* @brief 发送起始信号
*
*/
void Dri_IIC_Start();
/**
* @brief 发送一个字节的数据
*
* @param byte 要发送的数据
*/
void Dri_IIC_SendByte(u8 byte);
/**
* @brief 接收确认信号
*
* @return bit 返回接收到确认信号
*/
bit Dri_IIC_ReceiveACK();
/**
* @brief 接收一个字节的数据
*
* @return u8 接收到的数据
*/
u8 Dri_IIC_ReceiveByte();
/**
* @brief 发送确认信号
*
* @param ack 确认信号
*/
void Dri_IIC_SendACK(bit ack);
/**
* @brief 发送停止信号
*
*/
void Dri_IIC_Stop();
#endif /* __DRI_IIC_H__ */
c
#include "Dri_IIC.h"
/**
* @brief 发送起始信号
*
*/
void Dri_IIC_Start()
{
// 确保是空闲状态
SCL = 1;
SDA = 1;
// 将SDA拉低,发送起始信号
SDA = 0;
// 拉低时钟,方便下一步操作
SCL = 0;
}
/**
* @brief 发送一个字节的数据
*
* @param byte 要发送的数据
*/
void Dri_IIC_SendByte(u8 byte)
{
/*
第一次发送(最高位): (byte & 0b10000000) == 0 ? 0 : 1
第二次发送(次高位): (byte & 0b01000000) == 0 ? 0 : 1
第三次发送(第三高位): (byte & 0b0010000) == 0 ? 0 : 1
...
最后一次发送(最低位):(byte & 0b0000001) == 0 ? 0 : 1
*/
u8 i;
for (i = 0; i < 8; i++)
{
SDA = (byte & (0x80 >> i)) == 0 ? 0 : 1;
SCL = 1;
SCL = 0;
}
}
/**
* @brief 接收确认信号
*
* @return bit 返回接收到确认信号
*/
bit Dri_IIC_ReceiveACK()
{
bit ack;
// 主设备释放SDA(将其拉高)
SDA = 1;
// 主设备读取SDA
SCL = 1;
ack = SDA;
// 拉低SCL
SCL = 0;
return ack;
}
/**
* @brief 接收一个字节的数据
*
* @return u8 接收到的数据
*/
u8 Dri_IIC_ReceiveByte()
{
/*
第一次: xxxxxxxx | SDA(a) = xxxxxxxa
第二次: xxxxxxa0 | SDA(b) = xxxxxxab
第三次: xxxxxab0 | SDA(c) = xxxxxabc
...
第八次:abcdefg0 | SDA(h) = abcdefgh
*/
u8 byte = 0; // 保存接收到一个字节的数据
u8 i;
// 主设备释放SDA(拉高)
SDA = 1;
// 逐比特接收数据,共接收8次,先接收高位
for (i = 0; i < 8; i++)
{
SCL = 1;
// 先byte左移1位
byte <<= 1;
// 将SDA放在byte目前的最低位上
byte |= SDA;
SCL = 0;
}
// 返回
return byte;
}
/**
* @brief 发送确认信号
*
* @param ack 确认信号
*/
void Dri_IIC_SendACK(bit ack)
{
SDA = ack;
SCL = 1;
SCL = 0;
}
/**
* @brief 发送停止信号
*
*/
void Dri_IIC_Stop()
{
SDA = 0;
SCL = 1;
SDA = 1;
}
Dri_Timer0
c
#ifndef __DRI_TIMER0_H__
#define __DRI_TIMER0_H__
#include <STDIO.H>
#include "Com_Util.h"
// 定义Timer0最多可注册回调函数的数量
#define MAX_CALLBACK_COUNT 4
// 给函数指针类型取别名
typedef void (*Timer0_Callback)(void);
/**
* @brief 定时器0初始化
*/
void Dri_Timer0_Init();
/**
* @brief 注册定时器0的回调函数
*
* @param cb 回调函数的地址
* @return 1表示注册成功,0表示注册失败
*/
bit Dri_Timer0_RegisterCallback(Timer0_Callback cb);
/**
* @brief 解除指定的定时器0的回调函数
*
* @param cb 要解除回调函数的地址
* @return 1表示解除注册成功,0表示解除注册失败
*/
bit Dri_Timer0_DeregisterCallback(Timer0_Callback cb);
#endif /* __DRI_TIMER0_H__ */
c
#include "Dri_Timer0.h"
// 定义函数指针数组,每个元素都是 Timer0_Callback 类型
static Timer0_Callback s_timer0_callbacks[MAX_CALLBACK_COUNT] = {NULL, NULL, NULL, NULL};
/**
* @brief 定时器0初始化
*/
void Dri_Timer0_Init()
{
// 1. 打开总开关和定时器0的开关
EA = 1;
ET0 = 1;
// 2. 设置脉冲来源、工作模式、GATE
TMOD &= 0xF0;
TMOD |= 0x01; // GATE=0, C/T=0, M1、M0 = 01 16位脉冲计数器(不会自动重装载)
// 3. 计算脉冲计数器的初始值
TL0 = 64614;
TH0 = 64614 >> 8;
// 4. 设置定时器0的优先级(使用默认)
// 5. 开始计数
TR0 = 1;
}
/**
* @brief 注册定时器0的回调函数
*
* @param cb 回调函数的地址
* @return 1表示注册成功,0表示注册失败
*/
bit Dri_Timer0_RegisterCallback(Timer0_Callback cb)
{
u8 i;
// 如果回调函数已经注册过,直接返回0
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] == cb)
{
return 0;
}
}
// 将回调函数添加到第一个不是NULL的位置
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] == NULL)
{
s_timer0_callbacks[i] = cb;
return 1;
}
}
return 0;
}
/**
* @brief 解除指定的定时器0的回调函数
*
* @param cb 要解除回调函数的地址
* @return 1表示解除注册成功,0表示解除注册失败
*/
bit Dri_Timer0_DeregisterCallback(Timer0_Callback cb)
{
u8 i;
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] == cb)
{
s_timer0_callbacks[i] = NULL;
return 1;
}
}
return 0;
}
// 定义Timer0的中断服务程序
void Timer0_Handler() interrupt 1
{
u8 i;
// 重置脉冲计数器的初始值
TL0 = 64614;
TH0 = 64614 >> 8;
// 依次调用回调函数
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] != NULL)
{
s_timer0_callbacks[i]();
}
}
}
Int
c
#ifndef __INT_OLED_H__
#define __INT_OLED_H__
#include "Com_Util.h"
#include "Dri_IIC.h"
#define OLED_ADDR 0x78
//完成初始化
void Int_OLED_Init();
//清屏幕
void Int_OLED_Clear();
//指定位置显示指定字符串
void Int_OLED_DisplayString(u8 *str,u8 x, u8 y);
//在指定位置显示指定的数字
void Int_OLED_DisplayNumber(long num,u8 x, u8 y);
#endif /* __INT_OLED_H__ */
c
# include "Int_OLED.h"
// 定义字模信息(大小写字母、数字、标点符号)
// 加上关键字code 只适合C51 会将数据存储到程序空间
static code u8 s_font_bitmaps[][16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, //! 1
0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //" 2
0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00,
0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3
0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00,
0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, //$ 4
0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00,
0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, //% 5
0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00,
0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, //& 6
0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //' 7
0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, //( 8
0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, //) 9
0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00,
0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, //* 10
0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, //+ 11
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, //, 12
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //- 13
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, //. 14
0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04,
0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, /// 15
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16
0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17
0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00,
0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18
0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00,
0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19
0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00,
0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20
0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00,
0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21
0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00,
0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22
0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23
0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00,
0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25
0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, //: 26
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, //; 27
0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00,
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, //< 28
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, //= 29
0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00,
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, //> 30
0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, //? 31
0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00,
0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, //@ 32
0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00,
0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33
0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34
0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35
0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38
0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00,
0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40
0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41
0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00,
0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42
0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00,
0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43
0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44
0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00,
0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45
0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08,
0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47
0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00,
0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49
0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50
0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00,
0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51
0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00,
0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53
0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08,
0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54
0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00,
0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55
0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08,
0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56
0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00,
0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57
0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58
0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, //[ 59
0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, //\ 60
0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, //] 61
0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //^ 62
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, //_ 63
0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //` 64
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65
0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67
0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69
0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71
0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72
0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73
0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00,
0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74
0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75
0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77
0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81
0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83
0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84
0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86
0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80,
0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87
0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90
0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, //{ 91
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, //| 92
0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, //} 93
0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //~ 94
};
//发送多个数据字节
//bytes 表示要送的多个数据字节
//len 要发送的字节个数
//is_data 1是数据 0表示命令
static void Int_OLED_SendDataByte(u8 *bytes,u8 len,bit is_data)
{
u8 i;
//发送起始信号
Dri_IIC_Start();
//发送从设备地址和写标志,并接受确认信号
Dri_IIC_SendByte(OLED_ADDR);
Dri_IIC_ReceiveACK();
//发送控制字节 发数据 0100 0000 发命令 0000 0000
Dri_IIC_SendByte(is_data ? 0x40 : 0x00);
Dri_IIC_ReceiveACK();
//循环发送多个数据
for ( i = 0; i < len; i++)
{
Dri_IIC_SendByte(bytes[i]);
Dri_IIC_ReceiveACK();
}
//发送结束信号
Dri_IIC_Stop();
}
//发命令
static void Int_OLED_WriteCommand(u8 *cmds, u8 len)
{
Int_OLED_SendDataByte(cmds,len,0);
}
//发数据
static void Int_OLED_WriteData(u8 *cmds, u8 len)
{
Int_OLED_SendDataByte(cmds,len,1);
}
//页寻址模式下,设置页地址和列地址
static void Int_OLED_SetAddress(u8 page_addr, u8 column_addr)
{
u8 commands[3];
//设置页寻址模式,默认是页寻址,可以省略
//设置页地址
commands[0] = 0xB0 + page_addr;
//设置列地址
commands[1] = column_addr & 0x0F;
commands[2] = (column_addr>>4) + 0x10;
//发送命令
Int_OLED_WriteCommand(commands,3);
}
//完成初始化
void Int_OLED_Init()
{
//将六个命令存储在一个字符数组中,这六个负责OLED的初始化
u8 commands[6];
//显示屏关闭
commands[0]=0xAE;
//列的重映射
commands[1]=0xA1;
//行的重映射
commands[2]=0xC8;
//
commands[3] = 0x8D;
commands[4] = 0x14;
//显示屏开启
commands[5]=0xAF;
//将初始命令通过IIC协议发送到OLED的驱动芯片
Int_OLED_WriteCommand(commands,6);
}
//通过水平寻址,清屏幕
void Int_OLED_Clear()
{
//水平寻址,发送一系列的命令
u8 commands[2];
u8 Data[16];
u8 i;
for ( i = 0; i < 16; i++)
{
Data[i] = 0x00;
}
//设置寻址模式为水平寻址
commands[0] = 0x20;
commands[1] = 0x00;
//设置起始页范围,因为起始值就是这个所以无需发送
// commands[2] = 0x22;
// commands[3] = 0x00;
// commands[4] = 0x07;
//设置起始列地址
// commands[5] = 0x21;
// commands[6] = 0x00;
// commands[7] = 0xFF;
//写入命令
Int_OLED_WriteCommand(commands,2);
//发送一系列的数据
for ( i = 0; i < 64; i++)
{
Int_OLED_WriteData(Data,16);
}
}
//指定位置显示指定字符串
void Int_OLED_DisplayString(u8 *str,u8 x, u8 y)
{
u8 i;
//写入字符串的上半部分 x是列,y是行
//页寻址模式下设置页地址和列地址
Int_OLED_SetAddress(y*2,x*8);
//写入字符串,有效字符没有到达页边界
for(i=0 ;str[i]!='\0'&& i+x<16;i++)
{
Int_OLED_WriteData(s_font_bitmaps[ str[i]- 32],8);
}
//写入字符串的下半部分
Int_OLED_SetAddress((y*2)+1,x*8);
for(i=0 ;str[i]!='\0'&& i+x<16;i++)
{
Int_OLED_WriteData(s_font_bitmaps[ str[i]- 32] + 8,8);
}
}
//在指定位置显示指定的数字
void Int_OLED_DisplayNumber(long num,u8 x, u8 y)
{
u8 str[11] = {0,0,0,0,0,0,0,0,0,0,0};
sprintf(str,"%ld",num);
Int_OLED_DisplayString(str,x,y);
}
main
c
#include "Int_OLED.h"
#include "Com_Util.h"
void main()
{
P46 = 0;
Int_OLED_Init();
Int_OLED_Clear();
Int_OLED_DisplayString("hello GSX",0,0);
Int_OLED_DisplayString("I'm Fine",0,1);
Int_OLED_DisplayNumber(19990428,0,2);
while (1);
}
附录
51单片存储类型关键字
以下是 8051 C51 编程中常用存储类型关键字及其作用的表格:
| 关键字 | 存储位置 | 访问方式 | 适用场景 | 特点 |
|---|---|---|---|---|
code |
程序空间(ROM/Flash) | 只读 | 存储常量、查找表 | 不能在运行时修改 |
data |
内部 RAM(直接地址区) | 快速访问 | 频繁使用的小型数据存储 | 访问速度快,节省代码空间 |
idata |
内部 RAM(间接地址区) | 间接访问 | 非常用的变量存储 | 可用整个内部 RAM |
bdata |
位寻址 RAM | 位寻址 | 存储按位访问的标志位 | 可以逐个位访问 |
pdata |
外部 RAM 的页地址区 | 间接访问 | 存储少量外部 RAM 数据 | 需通过页选择寄存器访问 |
xdata |
外部 RAM | 间接访问 | 存储大数据块 | 可访问外部扩展 RAM |
hdata |
高位外部 RAM 区 | 间接访问 | 存储大量数据 | 访问外部 RAM 的高位区域 |
相关单词
Graphic 图形
segment 段选
continuation 连续
缩写名词
LSB(Least Significant Bit)最低有效位
MSB(Most Significant Bit)最高有效位
51扩展板引脚参考
| 引脚 | 对应模块 |
|---|---|
| P00 ~ P01 | 流水灯 / 数码管段选 |
| P10 | 595 SER输入 |
| P11 | 595 RCK输入 |
| P12 | 595 SCK输入 |
| P13 ~ P15 | 数码管位选 |
| P16 | I²C 数据线 |
| P17 | I²C 时钟线 |
| P20 ~ P23 | 矩阵按键 1 ~ 4 行 |
| P24 ~ P27 | 矩阵按键 1 ~ 4 列 |
| P30/RxD | 串口数据接收端 |
| P31/TxD | 串口数据发送端 |
| P32 | 独立按键SW3 / 外部中断0 / Timer0计数启动 |
| P33 | 独立按键SW4 / 外部中断1 / Timer1计数启动 |
| P34 | 流水灯开关(1开) / Timer0脉冲源 |
| P35 | Timer1脉冲源 / 点阵LED开关(0开) |
| P36 | 数码管开关(0开) |
| P42 | 独立按键SW1 / 外部中断3 |
| P43 | 独立按键 SW2 / 外部中断2 |
| P46 | 蜂鸣器 |
Day32(2025-12.23--2024-10.28)
第 21 章 18B20


21.1 1-Wire 通信协议

== ① 概述==
异步、串行、半双工
== ② 初始化==
- 主设备发送复位脉冲(DQ=0),并至少持续480us
- 主设备释放DQ并等待15~60us (该时间之后,从设备才会发送存在脉冲)
- 主设备读取从设备存在脉冲(DQ数据),至少延时480us(等待时间+后面的采样时间)再进行后续的操作
== ③ 写操作(发送)==
c
1. 先发低位,再发高位
2. 每发送一个bit的数据:
2.1 主设备拉低DQ
2.2 主设备要在15us内,将当前的bit信息发送到DQ
2.3 发送1个bit的数据共需要持续60~120us
2.4 发送完一个bit的数据需要将DQ释放,并至少持续1us

== ④ 读操作(接收)==
c
1. 先接收低位,再接收高位
2. 每接收一个bit的数据:
2.1 主设备将DQ拉低,至少持续1us,然后释放DQ
2.2 延时15us,读取DQ上的数据(从设备会在DQ被释放15us之内发送DQ发送数据,此处延时10us,也可以)
2.3 接收1个bit的数据共需要持续60~120us

21.2 18B20 通信流程
== ① 初始化==
== ② 发送 ROM 命令==
== ③ 发送功能命令==
21.3 使用1Wire协议控制18B20测试温度,并使用IIC协议将温度显示再OLED上
Com
c
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__
#include <STC89C5xRC.H>
#include <INTRINS.H>
// 类型别名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/**
* @brief 延时函数,指定延时多少毫秒
*
* @param count 指定多少毫秒
*/
void Delayms(u16 count);
//延时60us
void Delay60us(void);
//延时480us
void Delay480us(void);
//延时15us
void Delay15us(void);
//延时6us
void Delay6us(void);
//延时10us
void Delay10us(void);
#endif
c
/*******************************************************************************
****文件路径 : \使用定时器中断控制LED实现流水灯效果\src\Com\Com_Util.c
****作者名称 : error: git config user.name & please set dead value or install git
****文件版本 : V1.0.0
****创建日期 : 2025-12-15 22:34:16
****简要说明 :
****
****版权信息 : 2025 by ${git_name}, All Rights Reserved.
********************************************************************************/
#include "Com_Util.h"
// 延时函数,指定延时多少毫秒
/*******************************************************************************
****函数功能:
****入口参数: count:
****出口参数:
****函数备注:
********************************************************************************/
void Delayms(u16 count)
{
u8 data i, j;
while (count)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j)
;
} while (--i);
count--;
}
}
void Delay480us(void) //@11.0592MHz
{
unsigned char data i;
_nop_();
i = 218;
while (--i);
}
void Delay60us(void) //@11.0592MHz
{
unsigned char data i;
i = 25;
while (--i);
}
void Delay15us(void) //@11.0592MHz
{
unsigned char data i;
i = 4;
while (--i);
}
void Delay6us(void) //@11.0592MHz
{
_nop_();
}
void Delay10us(void) //@11.0592MHz
{
unsigned char data i;
i = 2;
while (--i);
}
Dir
Dri_1Wire
c
#ifndef __DRI_1WIRE_H__
#define __DRI_1WIRE_H__
#include "Com_Util.h"
#define DQ P44
//初始化 bit是从设备的回应信号
bit Dri_1Wire_Init();
//向从设备写入一个字节的数据
void Dri_1Wire_WriteByte(u8 byte);
//主设备读取一个字节的数据
u8 Dri_1Wire_ReadByte();
#endif /* __DRI_1WIRE_H__ */
c
#include "Dri_1Wire.h"
//初始化 bit是从设备的回应信号
bit Dri_1Wire_Init()
{
bit result;
//主设备发送复位脉,拉低DQ,至少持续480us
DQ =0;
Delay480us();
//主设备释放DQ ,并等待60us
DQ = 1;
Delay60us();
//主设备读取从设备的存在脉冲
result = DQ;//DQ 是从设备发送的,我们只能控制主设备
//延时至少420us
Delay480us();
return result;
}
//向从设备写入一个字节的数据
void Dri_1Wire_WriteByte(u8 byte)
{
u8 i;
//逐个bit发送
for ( i = 0; i < 8; i++)
{
//主设备拉低DQ
DQ = 0;
Delay10us();
//主设备发送数据
DQ = byte & 0x01;
byte >>= 1;
//整个发送过程至少持续60us
Delay60us();
//主设备释放DQ
DQ = 1;
}
}
//主设备读取一个字节的数据
u8 Dri_1Wire_ReadByte()
{
u8 i;
u8 result= 0;
u8 temp = 0x00;
//逐个bit接收,先接收低位,再接受高位
for ( i = 0; i < 8; i++)
{
//主设备拉低DQ 至少1us
DQ = 0;
//主设备释放DQ 交给从设备
DQ = 1;
//主设备等待10us,给从设备时间向DQ发送数据
Delay10us();
temp = DQ;
temp <<= i;
result |= temp;
//接受的过程持续60us
Delay60us();
//读取完一个bit也拉高释放DQ
DQ = 1;
}
return result;
}
Dri_IIC
c
#ifndef __DRI_IIC_H__
#define __DRI_IIC_H__
#include "Com_Util.h"
#define SCL P17
#define SDA P16
/**
* @brief 发送起始信号
*
*/
void Dri_IIC_Start();
/**
* @brief 发送一个字节的数据
*
* @param byte 要发送的数据
*/
void Dri_IIC_SendByte(u8 byte);
/**
* @brief 接收确认信号
*
* @return bit 返回接收到确认信号
*/
bit Dri_IIC_ReceiveACK();
/**
* @brief 接收一个字节的数据
*
* @return u8 接收到的数据
*/
u8 Dri_IIC_ReceiveByte();
/**
* @brief 发送确认信号
*
* @param ack 确认信号
*/
void Dri_IIC_SendACK(bit ack);
/**
* @brief 发送停止信号
*
*/
void Dri_IIC_Stop();
#endif /* __DRI_IIC_H__ */
c
#include "Dri_IIC.h"
/**
* @brief 发送起始信号
*
*/
void Dri_IIC_Start()
{
// 确保是空闲状态
SCL = 1;
SDA = 1;
// 将SDA拉低,发送起始信号
SDA = 0;
// 拉低时钟,方便下一步操作
SCL = 0;
}
/**
* @brief 发送一个字节的数据
*
* @param byte 要发送的数据
*/
void Dri_IIC_SendByte(u8 byte)
{
/*
第一次发送(最高位): (byte & 0b10000000) == 0 ? 0 : 1
第二次发送(次高位): (byte & 0b01000000) == 0 ? 0 : 1
第三次发送(第三高位): (byte & 0b0010000) == 0 ? 0 : 1
...
最后一次发送(最低位):(byte & 0b0000001) == 0 ? 0 : 1
*/
u8 i;
for (i = 0; i < 8; i++)
{
SDA = (byte & (0x80 >> i)) == 0 ? 0 : 1;
SCL = 1;
SCL = 0;
}
}
/**
* @brief 接收确认信号
*
* @return bit 返回接收到确认信号
*/
bit Dri_IIC_ReceiveACK()
{
bit ack;
// 主设备释放SDA(将其拉高)
SDA = 1;
// 主设备读取SDA
SCL = 1;
ack = SDA;
// 拉低SCL
SCL = 0;
return ack;
}
/**
* @brief 接收一个字节的数据
*
* @return u8 接收到的数据
*/
u8 Dri_IIC_ReceiveByte()
{
/*
第一次: xxxxxxxx | SDA(a) = xxxxxxxa
第二次: xxxxxxa0 | SDA(b) = xxxxxxab
第三次: xxxxxab0 | SDA(c) = xxxxxabc
...
第八次:abcdefg0 | SDA(h) = abcdefgh
*/
u8 byte = 0; // 保存接收到一个字节的数据
u8 i;
// 主设备释放SDA(拉高)
SDA = 1;
// 逐比特接收数据,共接收8次,先接收高位
for (i = 0; i < 8; i++)
{
SCL = 1;
// 先byte左移1位
byte <<= 1;
// 将SDA放在byte目前的最低位上
byte |= SDA;
SCL = 0;
}
// 返回
return byte;
}
/**
* @brief 发送确认信号
*
* @param ack 确认信号
*/
void Dri_IIC_SendACK(bit ack)
{
SDA = ack;
SCL = 1;
SCL = 0;
}
/**
* @brief 发送停止信号
*
*/
void Dri_IIC_Stop()
{
SDA = 0;
SCL = 1;
SDA = 1;
}
Dri_Timer0
c
#ifndef __DRI_TIMER0_H__
#define __DRI_TIMER0_H__
#include <STDIO.H>
#include "Com_Util.h"
// 定义Timer0最多可注册回调函数的数量
#define MAX_CALLBACK_COUNT 4
// 给函数指针类型取别名
typedef void (*Timer0_Callback)(void);
/**
* @brief 定时器0初始化
*/
void Dri_Timer0_Init();
/**
* @brief 注册定时器0的回调函数
*
* @param cb 回调函数的地址
* @return 1表示注册成功,0表示注册失败
*/
bit Dri_Timer0_RegisterCallback(Timer0_Callback cb);
/**
* @brief 解除指定的定时器0的回调函数
*
* @param cb 要解除回调函数的地址
* @return 1表示解除注册成功,0表示解除注册失败
*/
bit Dri_Timer0_DeregisterCallback(Timer0_Callback cb);
#endif /* __DRI_TIMER0_H__ */
c
#include "Dri_Timer0.h"
// 定义函数指针数组,每个元素都是 Timer0_Callback 类型
static Timer0_Callback s_timer0_callbacks[MAX_CALLBACK_COUNT] = {NULL, NULL, NULL, NULL};
/**
* @brief 定时器0初始化
*/
void Dri_Timer0_Init()
{
// 1. 打开总开关和定时器0的开关
EA = 1;
ET0 = 1;
// 2. 设置脉冲来源、工作模式、GATE
TMOD &= 0xF0;
TMOD |= 0x01; // GATE=0, C/T=0, M1、M0 = 01 16位脉冲计数器(不会自动重装载)
// 3. 计算脉冲计数器的初始值
TL0 = 64614;
TH0 = 64614 >> 8;
// 4. 设置定时器0的优先级(使用默认)
// 5. 开始计数
TR0 = 1;
}
/**
* @brief 注册定时器0的回调函数
*
* @param cb 回调函数的地址
* @return 1表示注册成功,0表示注册失败
*/
bit Dri_Timer0_RegisterCallback(Timer0_Callback cb)
{
u8 i;
// 如果回调函数已经注册过,直接返回0
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] == cb)
{
return 0;
}
}
// 将回调函数添加到第一个不是NULL的位置
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] == NULL)
{
s_timer0_callbacks[i] = cb;
return 1;
}
}
return 0;
}
/**
* @brief 解除指定的定时器0的回调函数
*
* @param cb 要解除回调函数的地址
* @return 1表示解除注册成功,0表示解除注册失败
*/
bit Dri_Timer0_DeregisterCallback(Timer0_Callback cb)
{
u8 i;
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] == cb)
{
s_timer0_callbacks[i] = NULL;
return 1;
}
}
return 0;
}
// 定义Timer0的中断服务程序
void Timer0_Handler() interrupt 1
{
u8 i;
// 重置脉冲计数器的初始值
TL0 = 64614;
TH0 = 64614 >> 8;
// 依次调用回调函数
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_timer0_callbacks[i] != NULL)
{
s_timer0_callbacks[i]();
}
}
}
Int
Int_18B20
c
#ifndef __INT_18B20_H__
#define __INT_18B20_H__
#include "Dri_1Wire.h"
//获取测量的温度
char Int_18B20_GetTemperature();
//获取测量的温度
float Int_18B20_GetTemperatureFloat();
#endif /* __INT_18B20_H__ */
c
#include "Int_18B20.h"
//获取测量的温度
char Int_18B20_GetTemperature()
{
u8 ls_byte;
u8 ms_byte;
//初始化
Dri_1Wire_Init();
//ROM命令
Dri_1Wire_WriteByte(0xCC);
//发送温度转换命令
Dri_1Wire_WriteByte(0x44);
Dri_1Wire_Init();
Dri_1Wire_WriteByte(0xCC);
//发送读取暂存器命令
Dri_1Wire_WriteByte(0xBE);
ls_byte= Dri_1Wire_ReadByte();
ms_byte= Dri_1Wire_ReadByte();
ms_byte <<=4;
ls_byte >>=4;
ls_byte = ls_byte | ms_byte;
return ls_byte;
}
//获取测量的温度
float Int_18B20_GetTemperatureFloat()
{
u8 ls_byte;
u8 ms_byte;
//初始化
Dri_1Wire_Init();
//ROM命令
Dri_1Wire_WriteByte(0xCC);
//发送温度转换命令
Dri_1Wire_WriteByte(0x44);
//发送读取暂存器命令
Dri_1Wire_Init();
Dri_1Wire_WriteByte(0xCC);
Dri_1Wire_WriteByte(0xBE);
ls_byte= Dri_1Wire_ReadByte();
ms_byte= Dri_1Wire_ReadByte();
ms_byte <<=4;
ls_byte >>=4;
return (ls_byte | ms_byte) +(ls_byte & 0x0F)*0.0625;
}
Int_OLED
c
#ifndef __INT_OLED_H__
#define __INT_OLED_H__
#include "Com_Util.h"
#include "Dri_IIC.h"
#define OLED_ADDR 0x78
//完成初始化
void Int_OLED_Init();
//清屏幕
void Int_OLED_Clear();
//指定位置显示指定字符串
void Int_OLED_DisplayString(u8 *str,u8 x, u8 y);
//在指定位置显示指定的数字
void Int_OLED_DisplayNumber(long num,u8 x, u8 y);
#endif /* __INT_OLED_H__ */
c
# include "Int_OLED.h"
#include "STDIO.H"
// 定义字模信息(大小写字母、数字、标点符号)
// 加上关键字code 只适合C51 会将数据存储到程序空间
static code u8 s_font_bitmaps[][16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, //! 1
0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //" 2
0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00,
0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3
0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00,
0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, //$ 4
0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00,
0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, //% 5
0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00,
0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, //& 6
0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //' 7
0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, //( 8
0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, //) 9
0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00,
0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, //* 10
0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, //+ 11
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, //, 12
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //- 13
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, //. 14
0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04,
0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, /// 15
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16
0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17
0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00,
0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18
0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00,
0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19
0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00,
0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20
0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00,
0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21
0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00,
0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22
0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23
0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00,
0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25
0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, //: 26
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, //; 27
0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00,
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, //< 28
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, //= 29
0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00,
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, //> 30
0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, //? 31
0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00,
0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, //@ 32
0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00,
0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33
0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34
0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35
0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38
0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00,
0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40
0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41
0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00,
0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42
0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00,
0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43
0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44
0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00,
0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45
0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08,
0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47
0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00,
0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49
0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50
0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00,
0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51
0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00,
0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53
0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08,
0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54
0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00,
0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55
0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08,
0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56
0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00,
0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57
0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58
0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, //[ 59
0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, //\ 60
0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, //] 61
0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //^ 62
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, //_ 63
0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //` 64
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65
0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67
0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69
0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71
0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72
0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73
0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00,
0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74
0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75
0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77
0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81
0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83
0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84
0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86
0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80,
0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87
0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90
0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, //{ 91
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, //| 92
0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, //} 93
0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //~ 94
};
//发送多个数据字节
//bytes 表示要送的多个数据字节
//len 要发送的字节个数
//is_data 1是数据 0表示命令
static void Int_OLED_SendDataByte(u8 *bytes,u8 len,bit is_data)
{
u8 i;
//发送起始信号
Dri_IIC_Start();
//发送从设备地址和写标志,并接受确认信号
Dri_IIC_SendByte(OLED_ADDR);
Dri_IIC_ReceiveACK();
//发送控制字节 发数据 0100 0000 发命令 0000 0000
Dri_IIC_SendByte(is_data ? 0x40 : 0x00);
Dri_IIC_ReceiveACK();
//循环发送多个数据
for ( i = 0; i < len; i++)
{
Dri_IIC_SendByte(bytes[i]);
Dri_IIC_ReceiveACK();
}
//发送结束信号
Dri_IIC_Stop();
}
//发命令
static void Int_OLED_WriteCommand(u8 *cmds, u8 len)
{
Int_OLED_SendDataByte(cmds,len,0);
}
//发数据
static void Int_OLED_WriteData(u8 *cmds, u8 len)
{
Int_OLED_SendDataByte(cmds,len,1);
}
//页寻址模式下,设置页地址和列地址
static void Int_OLED_SetAddress(u8 page_addr, u8 column_addr)
{
u8 commands[3];
//设置页寻址模式,默认是页寻址,可以省略
//设置页地址
commands[0] = 0xB0 + page_addr;
//设置列地址
commands[1] = column_addr & 0x0F;
commands[2] = (column_addr>>4) + 0x10;
//发送命令
Int_OLED_WriteCommand(commands,3);
}
//完成初始化
void Int_OLED_Init()
{
//将六个命令存储在一个字符数组中,这六个负责OLED的初始化
u8 commands[6];
//显示屏关闭
commands[0]=0xAE;
//列的重映射
commands[1]=0xA1;
//行的重映射
commands[2]=0xC8;
//
commands[3] = 0x8D;
commands[4] = 0x14;
//显示屏开启
commands[5]=0xAF;
//将初始命令通过IIC协议发送到OLED的驱动芯片
Int_OLED_WriteCommand(commands,6);
}
//通过水平寻址,清屏幕
void Int_OLED_Clear()
{
//水平寻址,发送一系列的命令
u8 commands[2];
u8 Data[16];
u8 i;
for ( i = 0; i < 16; i++)
{
Data[i] = 0x00;
}
//设置寻址模式为水平寻址
commands[0] = 0x20;
commands[1] = 0x00;
//设置起始页范围,因为起始值就是这个所以无需发送
// commands[2] = 0x22;
// commands[3] = 0x00;
// commands[4] = 0x07;
//设置起始列地址
// commands[5] = 0x21;
// commands[6] = 0x00;
// commands[7] = 0xFF;
//写入命令
Int_OLED_WriteCommand(commands,2);
//发送一系列的数据
for ( i = 0; i < 64; i++)
{
Int_OLED_WriteData(Data,16);
}
}
//指定位置显示指定字符串
void Int_OLED_DisplayString(u8 *str,u8 x, u8 y)
{
u8 i;
//写入字符串的上半部分 x是列,y是行
//页寻址模式下设置页地址和列地址
Int_OLED_SetAddress(y*2,x*8);
//写入字符串,有效字符没有到达页边界
for(i=0 ;str[i]!='\0'&& i+x<16;i++)
{
Int_OLED_WriteData(s_font_bitmaps[ str[i]- 32],8);
}
//写入字符串的下半部分
Int_OLED_SetAddress((y*2)+1,x*8);
for(i=0 ;str[i]!='\0'&& i+x<16;i++)
{
Int_OLED_WriteData(s_font_bitmaps[ str[i]- 32] + 8,8);
}
}
//在指定位置显示指定的数字
void Int_OLED_DisplayNumber(long num,u8 x, u8 y)
{
u8 str[11] = {0,0,0,0,0,0,0,0,0,0,0};
sprintf(str,"%ld",num);
Int_OLED_DisplayString(str,x,y);
}
main
c
#include "Int_18B20.h"
#include "Int_OLED.h"
#include "Com_Util.h"
#include "STDIO.H"
// void main ()
// {
// char temperature;
// float temp1;
// char temp_str[17];
// P46 = 0;
// Int_OLED_Init();
// Int_OLED_Clear();
// while (1)
// {
// temperature= Int_18B20_GetTemperature();
// temp1 = Int_18B20_GetTemperatureFloat();
// Int_OLED_DisplayString("temperature",0 ,0);
// Int_OLED_DisplayNumber(temperature,0 ,1);
// sprintf(temp_str,"%.4f",temp1);
// Int_OLED_DisplayString(temp_str,0,2);
// }
// }
// 主函数
void main()
{
char temp;
float temp1;
char temp1_str[17];
P46= 0;
// 初始化OLED并清屏
Int_OLED_Init();
Int_OLED_Clear();
// 死循环
while (1)
{
// 发去测温命令
temp = Int_18B20_GetTemperature();
temp1 = Int_18B20_GetTemperatureFloat();
// 将温度信息显示在OLED
Int_OLED_DisplayString("Tempearture: ", 0, 0);
// temp整数
Int_OLED_DisplayNumber(temp, 0, 1);
// 小数
sprintf(temp1_str, "%.4f", temp1);
Int_OLED_DisplayString(temp1_str, 0, 2);
}
}
第 22 章 DS1302 实时时钟
22.1 通信协议(三线串行通信)
DS1302 实时时钟芯片主要使用的是一个类似于SPI (Serial Peripheral Interface)
的三线通信协议来与微控制器进行通信。
== ① 发送(写操作)==

== ② 接收(读操作)==

22.2 DS1302



22.3 使用3Wire协议设置,读取DS1320上的时间并显示在OLED上
Com
c
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__
#include <STC89C5xRC.H>
#include <INTRINS.H>
// 类型别名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/**
* @brief 延时函数,指定延时多少毫秒
*
* @param count 指定多少毫秒
*/
void Delayms(u16 count);
// 延时10us
void Delay10us(void);
// 延时60us
void Delay60us(void);
// 延时480us
void Delay480us(void);
void Delay50us(void); //@11.0592MHz
#endif
c
#include "Com_Util.h"
// 延时函数,指定延时多少毫秒
void Delayms(u16 count)
{
u8 data i, j;
while (count)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j)
;
} while (--i);
count--;
}
}
// 延时10us
void Delay10us(void) //@11.0592MHz
{
unsigned char data i;
i = 2;
while (--i);
}
// 延时60us
void Delay60us(void) //@11.0592MHz
{
unsigned char data i;
i = 25;
while (--i);
}
// 延时480us
void Delay480us(void) //@11.0592MHz
{
unsigned char data i;
_nop_();
i = 218;
while (--i);
}
void Delay50us(void) //@11.0592MHz
{
unsigned char data i;
_nop_();
i = 20;
while (--i);
}
Dri
Dri_1Wire
c
#ifndef __DRI_1WIRE_H__
#define __DRI_1WIRE_H__
#include "Com_Util.h"
#define DQ P44
/**
* @brief 初始化
*
* @return bit 从设备的回应信号
*/
bit Dri_1Wire_Init();
/**
* @brief 向从设备写入一个字节的数据
*
* @param byte 要写入的字节
*/
void Dri_1Wire_WiteByte(u8 byte);
/**
* @brief 读取一个字节的数据
*
* @return u8 读取到字节
*/
u8 Dri_1Wire_ReadByte();
#endif /* __DRI_1WIRE_H__ */
c
#include "Dri_1Wire.h"
/**
* @brief 初始化
*
* @return bit 从设备的回应信号
*/
bit Dri_1Wire_Init()
{
bit result;
// 主设备发送复位脉冲,拉低DQ,至少持续480us
DQ = 0;
Delay480us();
// 主设备释放DQ,并等待60us
DQ = 1;
Delay60us();
// 主设备读取从设备的存在脉冲
result = DQ;
// 延时至少420us,此处延时480us 也可以 (60 + 420 = 480)
Delay480us();
return result;
}
/**
* @brief 向从设备写入一个字节的数据
*
* @param byte 要写入的字节
*/
void Dri_1Wire_WiteByte(u8 byte)
{
u8 i;
// 循环,逐bit发送,先发低位再发高位
for (i = 0; i < 8; i++)
{
// 先拉低DQ
DQ = 0;
// 在15us之内向DQ发送当前bit,此处选择延时10us
Delay10us();
DQ = byte & 0x01; // byte将最低位赋值给DQ
byte >>= 1; // byte右移1位
// 发送1bit的持续时间是 60~120us, 此处延时60us
Delay60us();
// 发送完1bit数据,将DQ拉高
DQ = 1;
}
}
/**
* @brief 读取一个字节的数据
*
* @return u8 读取到字节
*/
u8 Dri_1Wire_ReadByte()
{
u8 byte = 0;
u8 i;
u8 b = 0;
// 逐bit接收,先接收低位,再接收高位
for (i = 0; i < 8; i++)
{
// 主设备拉低DQ,至少持续1us
DQ = 0;
// 主设备释放DQ,交给从设备
DQ = 1;
// 主设备等待15us,从设备会在15us之内向DQ发送数据, 这里延时10us
Delay10us();
b = DQ;
b <<= i;
byte |= b;
// 接收的过程持续60~120us
Delay60us();
// 读取完1个bit,拉高DQ
DQ = 1;
}
return byte;
}
Dri_3Wire
c
#ifndef __DRI_3WIRE_H__
#define __DRI_3WIRE_H__
#include "Com_Util.h"
#define CE P41
#define SCLK P37
#define IO P40
/**
* @brief 向1302写入一个字节(发送一个字节的数据)
*
* @param byte 要写入的字节
*/
void Dri_3Wire_WriteByte(u8 byte);
/**
* @brief 从1302中读取一个字节的数据(接收一个字节的数据)
*
* @return u8 接收的字节
*/
u8 Dri_3Wire_ReadByte();
#endif /* __DRI_3WIRE_H__ */
c
#include "Dri_3Wire.h"
/**
* @brief 向1302写入一个字节(发送一个字节的数据)
*
* @param byte 要写入的字节
*/
void Dri_3Wire_WriteByte(u8 byte)
{
u8 i;
SCLK = 0;
// 循环逐比特发送,先发低位,再发高位
for (i = 0; i < 8; i++)
{
IO = byte & 0x01;
SCLK = 1;
SCLK = 0;
byte >>= 1;
}
}
/**
* @brief 从1302中读取一个字节的数据(接收一个字节的数据)
*
* @return u8 接收的字节
*/
u8 Dri_3Wire_ReadByte()
{
u8 byte = 0;
u8 i;
// 循环,逐bit接收,先收低位,再收高位
for (i = 0; i < 8; i++)
{
if (IO)
{
byte |= (0x01 << i);
}
SCLK = 1;
SCLK = 0;
}
return byte;
}
Dri_IIC
c
#ifndef __DRI_IIC_H__
#define __DRI_IIC_H__
#include "Com_Util.h"
#define SCL P17
#define SDA P16
/**
* @brief 发送起始信号
*
*/
void Dri_IIC_Start();
/**
* @brief 发送一个字节的数据
*
* @param byte 要发送的数据
*/
void Dri_IIC_SendByte(u8 byte);
/**
* @brief 接收确认信号
*
* @return bit 返回接收到确认信号
*/
bit Dri_IIC_ReceiveACK();
/**
* @brief 接收一个字节的数据
*
* @return u8 接收到的数据
*/
u8 Dri_IIC_ReceiveByte();
/**
* @brief 发送确认信号
*
* @param ack 确认信号
*/
void Dri_IIC_SendACK(bit ack);
/**
* @brief 发送停止信号
*
*/
void Dri_IIC_Stop();
#endif /* __DRI_IIC_H__ */
c
#include "Dri_IIC.h"
/**
* @brief 发送起始信号
*
*/
void Dri_IIC_Start()
{
// 确保是空闲状态
SCL = 1;
SDA = 1;
// 将SDA拉低,发送起始信号
SDA = 0;
// 拉低时钟,方便下一步操作
SCL = 0;
}
/**
* @brief 发送一个字节的数据
*
* @param byte 要发送的数据
*/
void Dri_IIC_SendByte(u8 byte)
{
/*
第一次发送(最高位): (byte & 0b10000000) == 0 ? 0 : 1
第二次发送(次高位): (byte & 0b01000000) == 0 ? 0 : 1
第三次发送(第三高位): (byte & 0b0010000) == 0 ? 0 : 1
...
最后一次发送(最低位):(byte & 0b0000001) == 0 ? 0 : 1
*/
u8 i;
for (i = 0; i < 8; i++)
{
SDA = (byte & (0x80 >> i)) == 0 ? 0 : 1;
SCL = 1;
SCL = 0;
}
}
/**
* @brief 接收确认信号
*
* @return bit 返回接收到确认信号
*/
bit Dri_IIC_ReceiveACK()
{
bit ack;
// 主设备释放SDA(将其拉高)
SDA = 1;
// 主设备读取SDA
SCL = 1;
ack = SDA;
// 拉低SCL
SCL = 0;
return ack;
}
/**
* @brief 接收一个字节的数据
*
* @return u8 接收到的数据
*/
u8 Dri_IIC_ReceiveByte()
{
/*
第一次: xxxxxxxx | SDA(a) = xxxxxxxa
第二次: xxxxxxa0 | SDA(b) = xxxxxxab
第三次: xxxxxab0 | SDA(c) = xxxxxabc
...
第八次:abcdefg0 | SDA(h) = abcdefgh
*/
u8 byte = 0; // 保存接收到一个字节的数据
u8 i;
// 主设备释放SDA(拉高)
SDA = 1;
// 逐比特接收数据,共接收8次,先接收高位
for (i = 0; i < 8; i++)
{
SCL = 1;
// 先byte左移1位
byte <<= 1;
// 将SDA放在byte目前的最低位上
byte |= SDA;
SCL = 0;
}
// 返回
return byte;
}
/**
* @brief 发送确认信号
*
* @param ack 确认信号
*/
void Dri_IIC_SendACK(bit ack)
{
SDA = ack;
SCL = 1;
SCL = 0;
}
/**
* @brief 发送停止信号
*
*/
void Dri_IIC_Stop()
{
SDA = 0;
SCL = 1;
SDA = 1;
}
Int
Int_18B20
c
#ifndef __INT_18B20_H__
#define __INT_18B20_H__
#include "Dri_1Wire.h"
/**
* @brief 获取测量的温度
*
* @return char 测量的温度
*/
char Int_18B20_GetTempearture();
/**
* @brief 获取测量的温度
*
* @return char 测量的温度(浮点数)
*/
float Int_18B20_GetTempeartureFloat();
#endif /* __INT_18B20_H__ */
c
#include "Int_18B20.h"
/**
* @brief 获取测量的温度
*
* @return char 测量的温度
*/
char Int_18B20_GetTempearture()
{
u8 ls_byte;
u8 ms_byte;
// 1. 让18B20测温 ---------------------------------------------------------
// 初始化
Dri_1Wire_Init();
// ROM命令:跳过
Dri_1Wire_WiteByte(0xCC);
// 发送测温命令,让18b20将测温结果存入暂存器
Dri_1Wire_WiteByte(0x44);
// 2. 读取18B20温度暂存器中的值(上次的测温结果)-------------------------------
// 初始化
Dri_1Wire_Init();
// ROM命令:跳过
Dri_1Wire_WiteByte(0xCC);
// 发送读暂存器命令,读取测温结果
Dri_1Wire_WiteByte(0xBE);
// 接收数据
ls_byte = Dri_1Wire_ReadByte();
ms_byte = Dri_1Wire_ReadByte();
// 处理温度信息
return (ms_byte << 4) | (ls_byte >> 4);
}
/**
* @brief 获取测量的温度
*
* @return char 测量的温度(浮点数)
*/
float Int_18B20_GetTempeartureFloat()
{
u8 ls_byte;
u8 ms_byte;
// 1. 让18B20测温 ---------------------------------------------------------
// 初始化
Dri_1Wire_Init();
// ROM命令:跳过
Dri_1Wire_WiteByte(0xCC);
// 发送测温命令,让18b20将测温结果存入暂存器
Dri_1Wire_WiteByte(0x44);
// 2. 读取18B20温度暂存器中的值(上次的测温结果)-------------------------------
// 初始化
Dri_1Wire_Init();
// ROM命令:跳过
Dri_1Wire_WiteByte(0xCC);
// 发送读暂存器命令,读取测温结果
Dri_1Wire_WiteByte(0xBE);
// 接收数据
ls_byte = Dri_1Wire_ReadByte();
ms_byte = Dri_1Wire_ReadByte();
// 处理温度信息
return ((ms_byte << 4) | (ls_byte >> 4)) + (ls_byte & 0x0F) * 0.0625;
}
Int_DS1302
c
#ifndef __INT_DS1302_H__
#define __INT_DS1302_H__
#include "Com_Util.h"
#include "Dri_3Wire.h"
// 定义相关寄存器的地址+写标识,如果读+1
#define SECOND_REG 0x80
#define MINUTE_REG 0x82
#define HOUR_REG 0x84
#define DATE_REG 0x86
#define MONTH_REG 0x88
#define DAY_REG 0x8A
#define YEAR_REG 0x8C
#define WP_REG 0x8E
// 定义表示日期的结构体
typedef struct
{
u8 year;
u8 month;
u8 day_week;
u8 day_month;
u8 hour;
u8 minute;
u8 second;
} Struct_Date;
/**
* @brief DS1302初始化
*/
void Int_DS1302_Init();
/**
* @brief 设置日期
*
* @param date 表示日期的结构体变量
*/
void Int_DS1302_SetDate(Struct_Date date);
/**
* @brief 获取当前的日期时间
*
* @return Struct_Date 日期时间的结构体
*/
Struct_Date Int_DS1302_GetDate();
#endif /* __INT_DS1302_H__ */
c
#include "Int_DS1302.h"
// 设置寄存器的值,写入
static void Int_DS1302_SetRegValue(addr, u8 value)
{
// 打开读写使能
CE = 1;
// 写入控制字节
Dri_3Wire_WriteByte(addr);
// 写入数据字节
Dri_3Wire_WriteByte(value);
// 关闭读写使能
CE = 0;
}
// 读取寄存器的值,返回读取的寄存器值
static u8 Int_DS1302_GetRegValue(addr)
{
u8 value;
// 打开读写使能
CE = 1;
// 写入控制字节
Dri_3Wire_WriteByte(addr);
// 读取数据字节
value = Dri_3Wire_ReadByte();
// 关闭读写使能
CE = 0;
return value;
}
/**
* @brief DS1302初始化
*/
void Int_DS1302_Init()
{
CE = 0;
SCLK = 0;
IO = 0;
}
/**
* @brief 设置日期
*
* @param date 表示日期的结构体变量
*/
void Int_DS1302_SetDate(Struct_Date date)
{
// 关闭写保护
Int_DS1302_SetRegValue(WP_REG, 0x00);
// 将秒信号写入寄存器
Int_DS1302_SetRegValue(SECOND_REG, ((date.second / 10) << 4) | (date.second % 10));
// 将分钟信号写入寄存器
Int_DS1302_SetRegValue(MINUTE_REG, ((date.minute / 10) << 4) | (date.minute % 10));
// 将小时信号写入寄存器
Int_DS1302_SetRegValue(HOUR_REG, ((date.hour / 10) << 4) | (date.hour % 10));
// 将每月几号信号写入寄存器
Int_DS1302_SetRegValue(DATE_REG, ((date.day_month / 10) << 4) | (date.day_month % 10));
// 将星期几信号写入寄存器
Int_DS1302_SetRegValue(DAY_REG, date.day_week);
// 将月信息写入寄存器
Int_DS1302_SetRegValue(MONTH_REG, ((date.month / 10) << 4) | (date.month % 10));
// 将年信息写入寄存器
Int_DS1302_SetRegValue(YEAR_REG, ((date.year / 10) << 4) | (date.year % 10));
// 打开写保护
Int_DS1302_SetRegValue(WP_REG, 0x80);
}
/**
* @brief 获取当前的日期时间
*
* @return Struct_Date 日期时间的结构体
*/
Struct_Date Int_DS1302_GetDate()
{
// 定义结构体变量
Struct_Date date;
u8 temp;
// 年
temp = Int_DS1302_GetRegValue(YEAR_REG + 1);
date.year = (temp >> 4) * 10 + (temp & 0x0F);
// 月
temp = Int_DS1302_GetRegValue(MONTH_REG + 1);
date.month = (temp >> 4) * 10 + (temp & 0x0F);
// 日(每月第几天)
temp = Int_DS1302_GetRegValue(DATE_REG + 1);
date.day_month = (temp >> 4) * 10 + (temp & 0x0F);
// 星期几
temp = Int_DS1302_GetRegValue(DAY_REG + 1);
date.day_week = temp;
// 时
temp = Int_DS1302_GetRegValue(HOUR_REG + 1);
date.hour = (temp >> 4) * 10 + (temp & 0x0F);
// 分钟
temp = Int_DS1302_GetRegValue(MINUTE_REG + 1);
date.minute = (temp >> 4) * 10 + (temp & 0x0F);
// 秒
temp = Int_DS1302_GetRegValue(SECOND_REG + 1);
date.second = (temp >> 4) * 10 + (temp & 0x0F);
return date;
}
Int_OLED
c
#ifndef __INT_OLED_H__
#define __INT_OLED_H__
#include "Com_Util.h"
#include "Dri_IIC.h"
// 设备地址 0111100 + 写标志 0
#define OLED_ADDR 0x78
/**
* @brief OLED初始化
*
*/
void Int_OLED_Init();
/**
* @brief 清屏
*
*/
void Int_OLED_Clear();
/**
* @brief 在指定位置显示指定的字符串
*
* @param str 字符串
* @param x x坐标位置
* @param y y坐标位置
*/
void Int_OLED_DisplayString(u8 *str, u8 x, u8 y);
/**
* @brief 在指定位置显示指定的数字
*
* @param num 数字
* @param x x坐标位置
* @param y y坐标位置
*/
void Int_OLED_DisplayNumber(long num, u8 x, u8 y);
#endif /* __INT_OLED_H__ */
c
#include <STDIO.H>
#include "Int_OLED.h"
// 定义字模信息(大小写字母、数字、标点符号)
static code u8 s_font_bitmaps[][16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, //! 1
0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //" 2
0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00,
0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3
0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00,
0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, //$ 4
0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00,
0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, //% 5
0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00,
0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, //& 6
0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //' 7
0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, //( 8
0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, //) 9
0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00,
0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, //* 10
0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, //+ 11
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, //, 12
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //- 13
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, //. 14
0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04,
0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, /// 15
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16
0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17
0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00,
0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18
0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00,
0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19
0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00,
0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20
0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00,
0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21
0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00,
0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22
0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23
0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00,
0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25
0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, //: 26
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, //; 27
0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00,
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, //< 28
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, //= 29
0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00,
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, //> 30
0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, //? 31
0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00,
0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, //@ 32
0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00,
0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33
0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34
0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35
0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38
0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00,
0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40
0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41
0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00,
0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42
0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00,
0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43
0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44
0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00,
0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45
0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08,
0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47
0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00,
0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49
0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50
0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00,
0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51
0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00,
0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53
0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08,
0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54
0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00,
0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55
0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08,
0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56
0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00,
0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57
0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58
0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, //[ 59
0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, //\ 60
0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, //] 61
0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //^ 62
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, //_ 63
0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //` 64
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65
0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67
0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69
0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71
0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72
0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73
0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00,
0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74
0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75
0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77
0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81
0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83
0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84
0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00,
0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86
0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80,
0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87
0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90
0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, //{ 91
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, //| 92
0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, //} 93
0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //~ 94
};
/**
* @brief 发送多个数据字节
*
* @param bytes 要发送的多个字节
* @param len 要发送的字节个数
* @param is_data 1表示数据0表示命令
*/
static void Int_OLED_SendDataByte(u8 *bytes, u8 len, bit is_data)
{
u8 i;
// 发送起始信号
Dri_IIC_Start();
// 发送从设备地址和写标志并接收ACK信号
Dri_IIC_SendByte(OLED_ADDR);
Dri_IIC_ReceiveACK();
// 发送控制字节 发数据 01000000; 发命令 00000000
Dri_IIC_SendByte(is_data ? 0x40 : 0x00);
Dri_IIC_ReceiveACK();
// 循环发送多个数据字节
for (i = 0; i < len; i++)
{
Dri_IIC_SendByte(bytes[i]);
Dri_IIC_ReceiveACK();
}
// 发送停止信号
Dri_IIC_Stop();
}
// 发送命令
static void Int_OLED_WriteCommand(u8 *cmds, u8 len)
{
Int_OLED_SendDataByte(cmds, len, 0);
}
// 发数据
static void Int_OLED_WriteData(u8 *datas, u8 len)
{
Int_OLED_SendDataByte(datas, len, 1);
}
// 页寻址模式下,设置页地址和列地址
static void Int_OLED_SetAddress(u8 page_addr, u8 column_addr)
{
u8 commands[3];
// 1. 设置为页寻址模式,默认就是也寻址,此步可以省略
// 2. 设置页地址
commands[0] = 0xB0 + page_addr;
// 3. 设置列地址
commands[1] = column_addr & 0x0F; // 发送低4位
commands[2] = 0x10 + (column_addr >> 4);
// 写入命令
Int_OLED_WriteCommand(commands, 3);
}
/**
* @brief OLED初始化
*
*/
void Int_OLED_Init()
{
// 定义6个元素的字符数组保存命令
u8 commands[6];
// 显示屏关闭
commands[0] = 0xAE;
// 行和列的重映射
commands[1] = 0xC8;
commands[2] = 0xA1;
// 增加电荷泵
commands[3] = 0x8D;
commands[4] = 0x14;
// 显示屏开启
commands[5] = 0xAF;
// 向OLED驱动芯片写入命令
Int_OLED_WriteCommand(commands, 6);
}
/**
* @brief 清屏
*
*/
void Int_OLED_Clear()
{
u8 i = 0;
u8 datas[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// 1.发送一系列的命令-------------------------------------
u8 commands[2];
// 1.1 设置寻址模式为水平寻址
commands[0] = 0x20;
commands[1] = 0x00;
// 1.2 设置页范围, 默认就是 0b000 ~ 0b111,此处无需设置
// 1.3 设置列范围, 默认就是 0b0000000 ~ 0b1111111,此处无需设置
// 写入命令
Int_OLED_WriteCommand(commands, 2);
// 2.发送一系列的数据-------------------------------------
// 每次发16个字节,分64次
for (i = 0; i < 64; i++)
{
Int_OLED_WriteData(datas, 16);
}
}
/**
* @brief 在指定位置显示指定的字符串
*
* @param str 字符串
* @param x x坐标位置
* @param y y坐标位置
*/
void Int_OLED_DisplayString(u8 *str, u8 x, u8 y)
{
u8 i;
// 1.写入字符串的上半部分 ----------------------------------
// 1.1 页寻址模式下设置页地址和列地址
Int_OLED_SetAddress(y * 2, x * 8);
// 1.2 循环写入数据 有效字符且没有到达页边界
for (i = 0; str[i] != '\0' && x + i < 16; i++)
{
// 写入该字符的字模信息的前8个元素
Int_OLED_WriteData(s_font_bitmaps[str[i] - 32], 8);
}
// 2.写入字符串的下半部分 ----------------------------------
Int_OLED_SetAddress(y * 2 + 1, x * 8);
// 1.2 循环写入数据 有效字符且没有到达页边界
for (i = 0; str[i] != '\0' && x + i < 16; i++)
{
// 写入该字符的字模信息的后8个元素
Int_OLED_WriteData(s_font_bitmaps[str[i] - 32] + 8, 8);
}
}
/**
* @brief 在指定位置显示指定的数字
*
* @param num 数字
* @param x x坐标位置
* @param y y坐标位置
*/
void Int_OLED_DisplayNumber(long num, u8 x, u8 y)
{
u8 str[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
sprintf(str, "%ld", num);
Int_OLED_DisplayString(str, x, y);
}
main
c
#include <STDIO.H>
#include "Com_Util.h"
#include "Int_OLED.h"
#include "Int_18B20.h"
#include "Int_DS1302.h"
char *weeks[7] = {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
};
// 主函数
void main()
{
char tmp;
Struct_Date curr_date;
char first_line[17];
char second_line[17];
// 定义结构体变量
Struct_Date start_date = {24, 10, 1, 28, 17, 22, 55};
// 初始化OLED并清屏
Int_OLED_Init();
Int_OLED_Clear();
// 初始化1302
Int_DS1302_Init();
// 设置起始的时间
Int_DS1302_SetDate(start_date);
// 死循环
while (1)
{
// 获取温度信息
tmp = Int_18B20_GetTempearture();
// 获取时间信息
curr_date = Int_DS1302_GetDate();
// 显示第一行
sprintf(first_line, "20%02d/%02d/%02d %s", (int)curr_date.year, (int)curr_date.month, (int)curr_date.day_month, weeks[curr_date.day_week-1]);
Int_OLED_DisplayString(first_line, 0, 0);
// 显示第二行
sprintf(second_line, "%02d:%02d:%02d Tmp:%d", (int)curr_date.hour, (int)curr_date.minute, (int)curr_date.second, (int)tmp);
Int_OLED_DisplayString(second_line, 0, 1);
}
}
c
秒寄存器
分钟寄存器
小时寄存器
Date寄存器(每月第几天)
Day寄存器(每周第几天)
月寄存器
年寄存器
写保护寄存器
附录
c
wire 线
temperature 温度
51扩展板引脚参考
| 引脚 | 对应模块 |
|---|---|
| P00 ~ P01 | 流水灯 / 数码管段选 |
| P10 | 595 SER输入 |
| P11 | 595 RCK输入 |
| P12 | 595 SCK输入 |
| P13 ~ P15 | 数码管位选 |
| P16 | I²C 数据线 |
| P17 | I²C 时钟线 |
| P20 ~ P23 | 矩阵按键 1 ~ 4 行 |
| P24 ~ P27 | 矩阵按键 1 ~ 4 列 |
| P30/RxD | 串口数据接收端 |
| P31/TxD | 串口数据发送端 |
| P32 | 独立按键SW3 / 外部中断0 / Timer0计数启动 |
| P33 | 独立按键SW4 / 外部中断1 / Timer1计数启动 |
| P34 | 流水灯开关(1开) / Timer0脉冲源 |
| P35 | Timer1脉冲源 / 点阵LED开关(0开) |
| P36 | 数码管开关(0开) |
| P42 | 独立按键SW1 / 外部中断3 |
| P43 | 独立按键 SW2 / 外部中断2 |
| P44 | 1-wire总线 |
| P46 | 蜂鸣器 |
第 23 章关于通信协议的总结

51智能车
Day33(2025-12.24--2024-10.29)
第 1 章 架构设计

第 2 章 避障
2.1 基础准备
- 实现GPIO驱动代码
- 将定时器0改成定时器2, 保证回调函数在数组中连续存储
- 使用定时器2改造蜂鸣器
2.2 测距模块


① 硬件设计
P32引脚连接ECHO引脚, ECHO开始输出高电平,定时器0开始计数,ECHO高电平变电平的时候下降沿触发外部中断0
② 软件设计
c
1. 初始化
两个引脚设置为0;
注册定时器2的回调函数实现两次测距间隔大于100ms
定时器0相关配置,不触发中断只用来计数
外部中断0相关配置,优先级要高
2. 获取测距结果
死循环中不断调用不断获取
2.3 电机模块
51芯片通过控制驱动芯片,芯片驱动电机





① 硬件设计
c
1. 左电机
前进:A1提供方波输入作为高电平,A2输入低电平
后退:A2提供方波输入作为高电平,A1输入低电平
2. 右电机(与左电机镜像放置)
前进:B2提供方波输入作为高电平,B1输入低电平
后退:B1提供方波输入作为高电平,B2输入低电平
② 软件设计
c
1. 利用定时器回调函数,实现方波每40ms一个周期,根据速度值不同决定每个周期的高电平占比
2. 分别设置左电机和右电机的速度,速度不会突变,而是逐渐变化
3. 更新速度的函数需要在死循环中不断调用
2.4 应用层
如果前方障碍物小于200mm,转弯
3 遥控
3.1 蓝牙模块



① 蓝牙芯片 ECB01C
蓝牙芯片接收到单片机发送的数据:
- 如果是AT命令,自己处理
- 如果不是AT命令,透传给手机
蓝牙芯片接收到手机发送的数据:
直接透传给单片机
② 软件设计
- 单片机向蓝牙发送AT命令,修改蓝牙名称,只需要执行一次
- 单片机通电先检测蓝牙状态,如果蓝牙状态正常继续执行后续逻辑,如果蓝牙不正常不执行后续逻辑。
3.2 应用层
使用手机上的小程序向单片机发送单字节命令(命令先给蓝牙芯片,蓝牙芯片通过串口转发给单片机)
第 4 章 巡线
4.1 光电反射传感器模块
① 硬件设计
c
光电反射传感器发出红外线,并接收反射回来的红外线,不同颜色的物体对红外线的反射效果不同,白色反射效果最强,黑色最弱
光电反射传感器接收到的反射光线越强,电流通过性越好(阻值越小)
如果光电反射传感器下面是黑线,向比较器输入的电压较大,最终向单片机引脚输入高电平,LED灭
② 软件设计
c
车头向左偏,右边的传感器检测到黑线,得到正值的误差
车头向右偏,左边的传感器检测到黑线,得到负值的误差
4.2 应用层
① 使用误差纠偏
② 使用PID算法纠偏
Proportional: 比例、**Integral: **积分、**Derivative: **微分。





