C51
其中涉及到的一些知识点
delay
延时函数:51 单片机的时钟频率为 12 MHz,转换成 Hz 就是
Hz,也就是一个时钟周期可以执行 次指令,那么一次指令的耗时就是 而我们使用
delay(50000)
,花费的时间就是大概就是
50
毫秒(ms)600000
怎么来的while(t--)
循环需要 3 条指令: 加载t
值、减1
、判断循环条件 因此while(t--)
需要12
个时钟周期 (3
个指令 x4
个时钟周期)delay(50000)
中的循环需要执行 50000 次 所以总的时钟周期数 =50000 x 12 = 600000
点灯
闪烁
#include <reg52.h>
// 用sbit来定义一个I/O口
// 至于为什么是P0^0,因为这个是固定的,不同的单片机是不同的,要看单片机文档
sbit LED = P0 ^ 0;
void delay(unsigned int t)
{
while (t--);
}
void main(void)
{
while (1) {
// 将P0.0口赋值 0,该口电平为低,使LED亮
// 如果想赋值 1为亮,则根据半导体性质,将LED灯反过来接即可
// 下面代码每隔一段时间调整LED口的电压,实现闪烁功能
LED = 0;
delay(50000);
LED = 1;
delay(50000);
}
}
流水灯
#include <reg52.h>
void delay(unsigned int t)
{
while (t--);
}
void main(void)
{
int i;
while (1)
{
for (i = 0; i < 8; i++) {
/**
* 我们有8个LED灯,每次让一个LED灯亮,就是让该口的电压为0
* 数字 1 的二进制为 00000001,对他取反就是 11111110,很轻松
* 实现了一个灯的亮,1 左移1位的二进制是 00000010,取反就是
* 11111101 实现了第二个的灯亮,以此类推实现流水灯
*/
P0 = ~(1 << i);
delay(5000);
}
}
}
蜂鸣器
蜂鸣器的一些知识点
有源蜂鸣器只需要给他通电就可以发出声音,无源蜂鸣器需要输入对应的脉冲信号才能发出声音
单片机提供的电流很小,可能不能使蜂鸣器正常工作,所以需要三极管允许更大的电流通过,使的蜂鸣器正常工作
按键控制蜂鸣器
#include <reg52.h>
sbit BUZZER = P0 ^ 0;
sbit KEY = P2 ^ 0;
void delay(unsigned int t)
{
while (t--);
}
void main(void)
{
while (1) {
if (KEY == 0) {
delay(20);
if (KEY == 0) {
BUZZER = ~BUZZER;
}
}
}
}
选择有源蜂鸣器,将蜂鸣器的电压调整为 2V,打开电脑的声音,应该能听到蜂鸣器发出的声音
蜂鸣器播放音乐(生日快乐)
#include <reg52.h>
sbit BEEP = P0 ^ 0;
unsigned char code SONG_TONE[] = {212, 212, 190, 212, 159, 169, 212, 212, 190, 212, 142, 159, 212, 212, 106, 126, 129, 169, 190, 119, 119, 126, 159, 142, 159, 0};
unsigned char code SONG_LONG[] = {9, 3, 12, 12, 12, 24, 9, 3, 12, 12, 12, 24, 9, 3, 12, 12, 12, 12, 12, 9, 3, 12, 12, 12, 24, 0};
void delay(unsigned int t)
{
while (t--);
}
void PlayMusic()
{
unsigned int i = 0, j, k;
while (SONG_LONG[i] != 0 || SONG_TONE[i] != 0) {
for (j = 0; j < SONG_LONG[i] * 30; j++) {
BEEP = ~BEEP;
for (k = 0; k < SONG_TONE[i] / 3; k++);
}
delay(100);
i++;
}
}
void main()
{
while (1) {
PlayMusic();
delay(5000);
}
}
数码管
展示数字
我们选择的是共阳极数码管
#include <reg52.h>
void main(void)
{
while (1) {
P0 = 0xC0;
}
}
根据需要选择对应的值来展示不同的数字
数字滚动
#include <reg52.h>
void delay(unsigned int t)
{
while (t--);
}
int seg[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
void main(void)
{
int i;
while (1) {
for (i = 0; i < 10; i++) {
P0 = seg[i];
delay(50000);
}
}
}
动态扫描
#include <reg52.h>
void delay(unsigned int t)
{
while (t--);
}
int seg[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
void main(void)
{
int i;
int num;
while (1) {
num++;
for (i = 0; i < 4; i++) {
P2 = 1 << i;
if (i == 0) {
P0 = seg[num / 1000];
} else if (i == 1) {
P0 = seg[num % 1000 / 100];
} else if (i == 2) {
P0 = seg[num % 100 / 10];
} else if (i == 3) {
P0 = seg[num % 10];
}
/**
* 刷新率在50Hz以上,人眼差不多就无法分辨出来了,所以延迟要
* 少于某个阈值即可实现,500并非固定
*/
delay(500);
P0 = 0xff; // 消除拖影
}
if (num >= 9999) {
num = 0;
}
}
}
点阵
心
#include <reg52.h>
unsigned char hang[8] = {0xFF, 0x99, 0x00, 0x00, 0x00, 0x81, 0xC3, 0xE7};
unsigned char lie[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void delay(unsigned int t)
{
while (t--);
}
int main()
{
while (1) {
int i = 0;
for (i = 0; i < 8; i++) {
P2 = lie[i];
P0 = hang[i];
delay(300);
}
}
}
跳动的心
#include <reg52.h>
unsigned char hang[8] = {0xFF, 0x99, 0x00, 0x00, 0x00, 0x81, 0xC3, 0xE7};
unsigned char lie[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void delay(unsigned int t)
{
while (t--);
}
int main()
{
while (1) {
int i = 0;
for (i = 0; i < 8; i++) {
P2 = lie[i];
P0 = hang[i];
delay(300);
}
P2 = 0x00;
P0 = 0x00;
delay(60000);
}
}
按键
按键的一些知识点
消抖
独立按键为机械弹性开关,当按键的触点闭合,断开时,由于弹性作用,独立按键没有办法立刻保持稳定, 需要等待一定时间才能保持稳定,一般来说,这个抖动在 10 ~ 20ms 左右。
按键点灯
#include <reg52.h>
sbit LED = P0 ^ 0;
sbit KEY = P2 ^ 0;
void delay(unsigned int t)
{
while (t--);
}
void main(void)
{
while (1) {
// 独立按键默认是高电平,即没有按下去为高电平,按下去为低电平。
if (KEY == 0) { // 检测低电平,也就是按键是否按下
delay(20); // 消抖延时
if (KEY == 0) {
LED = ~LED;
while (!LED); // 防误触,按下了长时间未松开则不处理(可以不写)
}
}
}
}
按键实现数码管计数
#include <reg52.h>
sbit KEY = P3 ^ 0;
void delay(unsigned int t)
{
while (t--);
}
int seg[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
void showSEG(int num)
{
int i;
for (i = 0; i < 2; i++) {
P2 = 1 << i;
if (i == 0) {
P0 = seg[num / 10];
} else if (i == 1) {
P0 = seg[num % 10];
}
delay(500);
P0 = 0xff;
}
}
void main(void)
{
int num = 0;
while (1) {
if (KEY == 0) {
delay(20);
if (KEY == 0) {
if (num >= 99) {
num = 0;
} else
num++;
while (!KEY) {
showSEG(num);
}
}
}
showSEG(num);
}
}
矩阵键盘
#include <reg52.h>
sbit L0 = P1 ^ 0;
sbit L1 = P1 ^ 1;
sbit L2 = P1 ^ 2;
sbit L3 = P1 ^ 3;
void delay(unsigned int t)
{
while (t--);
}
int seg[16] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
int btn[4] = {0xef, 0xdf, 0xbf, 0x7f};
void showSEG(int num)
{
int i;
for (i = 0; i < 2; i++) {
P2 = 1 << i;
if (i == 0) {
P0 = seg[num / 10];
} else if (i == 1) {
P0 = seg[num % 10];
}
delay(500);
P0 = 0xff;
}
}
void main(void)
{
int num = 0;
int i, j;
while (1) {
for (i = 0; i < 4; i++) {
P1 = btn[i];
for (j = 0; j < 4; j++) {
if (L0 == 0) num = i * 4 + 1;
if (L1 == 0) num = i * 4 + 2;
if (L2 == 0) num = i * 4 + 3;
if (L3 == 0) num = i * 4 + 4;
}
showSEG(num);
delay(500);
}
}
}
定时器
#include <reg52.h>
sbit LED = P0 ^ 0;
void time0_init(void)
{
// 工作模式:GATE=0;C/T=0;M1=0,M0=1
TMOD |= 0x01;
// 初始值
TH0 = 0xfc;
TL0 = 0x18;
// 启动定时器
TR0 = 1;
}
void main(void)
{
time0_init();
while (1);
}
具体效果可以查看下方的 中断和定时器的结合
部分。
中断
中断的一些知识点
符号 | 描述 | 说明 | 具体描述 |
---|---|---|---|
EA | 中断总开关 | 为 1 时 CPU 开放 中断,为 0 时 CPU 屏蔽 所有中断申请 | |
EX0 | 外部中断 | 为 1 时 允许 外部中断,为 0 时 禁止 外部中断 | 见下方 EX0 |
IT0 | 外部中断 0 触发方式选择位 | 为 1 时下降沿触发,为 0 时低电平触发 |
EX0
- (此处为外部中断 0,还有其余的中断例如
EX1
,ET0
,ET1
,ES
) (ET0
/ET1
): 定时器中断 (ES
): 串口中断
interrupt 0
- 这里不是 C 基础语法,属于嵌入式的语法,用于处理中断 0,当中断 0 触发时,执行的函数
所以触发中断只需给对应的寄存器赋值,例如
EA = 1;
EX0 = 1;
IT0 = 1;
执行完成后,会触发 interrupt 0
声明的函数,即 abc
void abc() interrupt 0 {
}
中断实现按键点灯
#include <reg52.h>
sbit LED = P0 ^ 0;
sbit KEY = P3 ^ 2;
void it0_init()
{
EA = 1; // 总中断开
EX0 = 1; // IT0中断开
IT0 = 1; // TCON中控制INT0触发方式位,INT0下降沿触发中断
}
void it0_isr() interrupt 0
{
if (KEY == 0) LED = !LED;
}
void main(void)
{
it0_init(); // 中断初始化
while (1);
}
中断和定时器的结合
之前使用 delay
延时来进行 LED
灯的闪烁,这次我们通过更加精确的定时器来实现闪烁
#include <reg52.h>
sbit LED = P0 ^ 0;
void time0_init(void)
{
// 工作模式:GATE=0;C/T=0;M1=0,M0=1
TMOD |= 0x01;
// 初始值
TH0 = 0xfc;
TL0 = 0x18;
// 启动中断
EA = 1;
ET0 = 1;
// 启动定时器
TR0 = 1;
}
void time0() interrupt 1
{
static unsigned short i = 0;
// 初始化
TH0 = 0xfc;
TL0 = 0x18;
i++;
if (i == 500) {
i = 0;
LED = !LED;
}
}
void main(void)
{
time0_init();
while (1);
}
火灾报警器(对温度、光亮等敏感)
I2C 总线
I2C 总线的一些知识点
符号 | 描述 | 说明 | 具体描述 |
---|---|---|---|
SCL | 时钟线 | ||
SDA | 数据线 |
开始
:SCL
为高电平的时候,SDA
由高电平变为低电平,开始传送数据结束
:SCL
为高电平的时候,SDA
由低电平变为高电平,停止传输数据应答
: 接收者收到8
个bit
数据后,向发送者发出低电平脉冲,表示收到数据
实现 I2C 通信
#include <reg52.h>
#define SDA P1 ^ 0
#define SCL P1 ^ 1
#define DEV_ADDR 0x78
#define DATA_MODE 0x40
#define CMD_MODE 0x00
void delay(unsigned int t)
{
while (t--);
}
// 发送起始信号
void Dri_IIC_Start()
{
SCL = 1;
SDA = 1;
SDA = 0;
SCL = 0;
}
// 发送结束信号
void Dri_IIC_Stop()
{
SDA = 0;
SCL = 1;
SDA = 1;
}
// 发送一个字节
void Dri_IIC_SendByte(unsigned char byte)
{
unsigned char i;
for (i = 0; i < 8; i++) {
SDA = (byte & (0x80 >> i)) == 0 ? 0 : 1;
SCL = 1;
SCL = 0;
}
}
// 接收一个字节
unsigned char Dri_IIC_ReceiveByte()
{
unsigned char byte = 0;
unsigned char i;
SDA = 1;
for (i = 0; i < 8; i++) {
SCL = 1;
byte = (byte << 1) | SDA;
SCL = 0;
}
return byte;
}
// 接收确认信号
bit Dri_IIC_ReceiveAck()
{
bit ack;
SDA = 1;
SCL = 1;
ack = SDA;
SCL = 0;
return ack;
}
// 发送确认信号
void Dri_IIC_SendAck(bit ack)
{
SDA = ack;
SCL = 1;
SCL = 0;
}
void main()
{
unsigned char code Data[] = "abcdefghABCDEFGH";
while (1){
Dri_IIC_Start();
Dri_IIC_SendByte(DEV_ADDR);
Dri_IIC_ReceiveAck();
Dri_IIC_SendByte(DATA_MODE);
Dri_IIC_ReceiveAck();
for (i = 0; i < 16; i++) {
Dri_IIC_SendByte(Data[i]);
Dri_IIC_ReceiveAck();
}
Dri_IIC_Stop();
}
}
具体效果可以查看下方的 OLED
部分。
串口通信
实现 串口通信
#include <reg52.h>
unsigned char UartBuf = 0;
void SendStr(unsigned char *p);
void SendOneByte(unsigned char c);
void UsartInit()
{
SCON = 0x50; // 串口工作方式1,接收数据
TMOD = 0x20; // 定时器T1工作方式2
TH1 = TL1 = 0xF3; // 芯片频率为12MHz, 设置波特率为2400,在SMOD作用下加倍,4800
PCON = 0x80; // 波特率加倍
EA = 1; // 打开CPU中断允许位
ES = 1; // 打开串口中断允许位
TR1 = 1; // 启动计时器1
}
void main()
{
UsartInit();
while (1) {
if (UartBuf) {
SendStr("Hello, world!\r\n");
UartBuf = 0;
}
}
}
void ReceiveDat() interrupt 4
{
if (RI) {
RI = 0;
UartBuf = SBUF;
} else
TI = 0;
}
void SendOneByte(unsigned char c)
{
SBUF = c;
while (!TI);
TI = 0;
}
void SendStr(unsigned char *p)
{
while (*p != '\0') {
SendOneByte(*p);
p++;
}
}
波特率为 4800
,芯片频率用的 12MHz
LCD 显示屏
其中涉及到的一些知识点
符号 | 描述 | 说明 | 具体描述 |
---|---|---|---|
VSS | 电源地 | 接地 | |
VDD | 电源正极 | 接电源正极 | |
VEE/VL | 液晶显示偏压信号 | 接地,也可以接一个滑动变阻器来控制亮度 | |
RS | 数据/命令选择 | 为 1 时传 数据 ,为 0 时传 命令 | 见下方 RS |
RW | 读/写选择 | 为 1 时 读 ,为 0 时 写 | |
E | 使能信号 | 为 0 时 显示屏工作,为 1 时 停止工作 | |
D0 ~ D7 | 数据 | 显示的字符 | 见下方 编码 |
RS
RS
信号决定了当前的操作是数据
传送还是命令
传送,其中传数据
是指显示屏上显示什么字符,传命令
是指在哪显示。
编码
- 显示字符时,需要将字符转换为对应的二进制数,然后通过
D0
到D7
输出。字模编码见下图,低四位为横坐标,高四位为纵坐标。
指令表
注意
下面的代码中我们的数据 Data
首末尾都有三个空字符,所以在 LCD_Write_Cmd
写入 0x00
如果去除掉 Data
的空格,那么更改为 0x03
即可.
为什么要加 0x80
?
- 在指令集中,所有的指令都有一位是
1
,LCD1602
就是用他来区分是哪一条指令的,其中 指令 8 就是第七位为1
,所以加上0x80
就是在屏幕 第一行第一个位置显示字符以此类推,即可控制在哪显示。
void main()
{
unsigned char code Data[] = " I Love You "; // "I Love You "
unsigned char i;
LCD_Init();
LCD_Write_Cmd(0x00 + 0x80); // LCD_Write_Cmd(0x03 + 0x80)
for (i = 0; i < 16; i++) {
LCD_Write_Data(Data[i]);
}
while (1);
}
显示字符
#include <reg52.h>
#define LCD_Data P0
sbit LCD_RS = P2 ^ 0;
sbit LCD_RW = P2 ^ 1;
sbit LCD_E = P2 ^ 2;
void delay(unsigned int t)
{
while (t--);
}
void main()
{
unsigned char code Data[] = " I Love You "; // 第一行显示,共十六个字符
unsigned char i;
LCD_Init(); // LCD1602 初始化
LCD_Write_Cmd(0x00 + 0x80); // 第一行第一列地址,0x00 可以省去
for (i = 0; i < 16; i++) {
LCD_Write_Data(Data[i]);
}
while (1);
}
// 初始化
void LCD_Init()
{
LCD_Write_Cmd(0x01); // 指令1 ——清屏
LCD_Write_Cmd(0x06); // 指令3 ——AC加1,画面不动
LCD_Write_Cmd(0x0c); // 指令4 ——显示开,光标关,闪烁关
LCD_Write_Cmd(0x38); // 指令6 ——8位数据接口,两行显示,5X7点阵
LCD_Write_Cmd(0x80); // 指令8 ——从第一行第一列开始显示
}
// 写命令
void LCD_Write_Cmd(unsigned char Cmd)
{
LCD_Check_Busy(); // 判忙
LCD_RS = 0; // 0 指令
LCD_RW = 0; // 0 写
LCD_E = 0;
LCD_Data = Cmd; // 送指令
delay(1000);
LCD_E = 1; // 拉高
delay(1000);
LCD_E = 0;
}
// 写数据
void LCD_Write_Data(unsigned char Data)
{
LCD_Check_Busy(); // 判忙
LCD_RS = 1; // 1 数据
LCD_RW = 0; // 0 写
LCD_E = 0;
LCD_Data = Data; // 送数据
delay(1000);
LCD_E = 1; // 拉高
delay(1000);
LCD_E = 0;
}
// 忙检测
void LCD_Check_Busy()
{
unsigned char temp;
LCD_Data = 0xff; // 十六进制:1111 1111
LCD_RS = 0; // 0 指令
LCD_RW = 1; // 1 读
do {
LCD_E = 1; // 拉高
temp = LCD_Data; // 将 LCD 状态保存在 temp 中,用于判忙
LCD_E = 0; // 负跳变使能
} while (temp & 0x80); // 结果为 1,LCD 忙,继续循环;结果为 0,LCD 不忙,可以进行后面的操作
}
因为使用的是 P0
口,所以需要右下角的上拉电阻,如果使用别的口,则不需要。
显示两行字符
扩展方法
/**
* @brief 设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line, unsigned char Column)
{
if (Line == 1) {
LCD_Write_Cmd(0x80 | (Column - 1));
} else if (Line == 2) {
LCD_Write_Cmd(0x80 | (Column - 1 + 0x40));
}
}
/**
* @brief 返回值: X的Y次方
*/
int LCD_Pow(int X, int Y)
{
unsigned char i;
int Result = 1;
for (i = 0; i < Y; i++) {
Result *= X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line, Column);
for (i = Length; i > 0; i--) {
LCD_Write_Data(Number / LCD_Pow(10, i - 1) % 10 + '0');
}
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line, unsigned char Column, char *String)
{
unsigned char i;
LCD_SetCursor(Line, Column);
for (i = 0; String[i] != '\0'; i++) {
LCD_Write_Data(String[i]);
}
}
这时候可以这样显示两行字符:
void main()
{
LCD_Init();
while (1) {
LCD_ShowString(1, 1, " I Love You ");
LCD_ShowString(2, 1, "abcdefghigklmnopqRSTuvwxyz"); // 显示时
}
}
void main()
{
unsigned char code Data_1[] = " I Love You "; // 第一行显示
unsigned char code Data_2[] = "abcdefghABCDEFGH"; // 第二行显示
unsigned char i;
LCD_Init(); // LCD1602 初始化
LCD_Write_Cmd(0x00 + 0x80); // 第一行第一列地址,0x00 可以省去
for (i = 0; i < 16; i++) {
LCD_Write_Data(Data_1[i]);
}
LCD_Write_Cmd(0x40 + 0x80); // 第二行第一列地址
for (i = 0; i < 16; i++) {
LCD_Write_Data(Data_2[i]);
}
while (1);
}
画面移动
void main()
{
unsigned char code Data[] = "abcdefghigklmnopqrstuvwxyz";
unsigned char i;
LCD_Init(); // LCD1602 初始化
LCD_Write_Cmd(0x00 + 0x80); // 第一行第一列地址,0x00 可以省去
for (i = 0; i < 26; i++) {
LCD_Write_Data(Data[i]);
}
while (1) {
delay(500000); // 控制移动速度
LCD_Write_Cmd(0x18); // 指令5 ——画面左移一个字符位,光标不动
}
}
OLED 显示屏
显示字符
对应的字符集
const unsigned char code OLED_Font[][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
};
void main()
{
OLED_Init();
OLED_Clear();
OLED_ShowChar(0, 0, 'A');
OLED_ShowStr(0, 1, "Hello world!");
OLED_ShowNum(0, 2, -123459, 6);
while (1);
}
//初始化
void Int_OLED_Init()
{
unsigned char cmd_bytes[6];
// 关闭屏幕
cmd_bytes[0] = 0xAE;
// 行重映射
cmd_bytes[1] = 0xC8;
// 列重映射
cmd_bytes[2] = 0xA1;
// 电荷泵
cmd_bytes[3] = 0x8D;
cmd_bytes[4] = 0x14;
// 开启屏幕
cmd_bytes[5] = 0xAF;
Int_OLED_WriteCmd(cmd_bytes, 6);
}
//清零
void Int_OLED_Clear()
{
unsigned short int i;
unsigned char data_bytes[8] = {0};
unsigned char cmd_bytes[2];
// 设置寻址模式 水平寻址-默认值,省略
cmd_bytes[0] = 0x20;
cmd_bytes[1] = 0x00;
Int_OLED_WriteCmd(cmd_bytes, 2);
// 直接写入数据
Dri_IIC_Start();
Dri_IIC_SendByte(DEV_ADDR);
Dri_IIC_ReceiveAck();
Dri_IIC_SendByte(DATA_MODE);
Dri_IIC_ReceiveAck();
for (i = 0; i < 128 * 8; i++) {
Dri_IIC_SendByte(0x00);
Dri_IIC_ReceiveAck();
}
Dri_IIC_Stop();
}
//写命令
void Int_OLED_WriteCmd(unsigned char bytes[], unsigned char length)
{
unsigned char i;
Dri_IIC_Start();
Dri_IIC_SendByte(DEV_ADDR);
Dri_IIC_ReceiveAck();
Dri_IIC_SendByte(CMD_MODE);
Dri_IIC_ReceiveAck();
for (i = 0; i < length; i++) {
Dri_IIC_SendByte(bytes[i]);
Dri_IIC_ReceiveAck();
}
Dri_IIC_Stop();
}
//写数据
void Int_OLED_WriteData(unsigned char bytes[], unsigned char length)
{
unsigned char i;
Dri_IIC_Start();
Dri_IIC_SendByte(DEV_ADDR);
Dri_IIC_ReceiveAck();
Dri_IIC_SendByte(DATA_MODE);
Dri_IIC_ReceiveAck();
for (i = 0; i < length; i++) {
Dri_IIC_SendByte(bytes[i]);
Dri_IIC_ReceiveAck();
}
Dri_IIC_Stop();
}
// 设置起始位置函数
void Int_OLED_SetPointer(unsigned char page, unsigned char column)
{
unsigned char cmd_bytes[3];
// 页地址
cmd_bytes[0] = 0xB0 | page;
// 列地址
cmd_bytes[1] = 0x0F & column;
cmd_bytes[2] = 0x10 | (column >> 4);
// 发送指令
Int_OLED_WriteCmd(cmd_bytes, 3);
}
//显示字符
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char chr)
{
unsigned char cmd_bytes[2];
// 设置OLED寻址方式
cmd_bytes[0] = 0x20; // 设置寻址模式命令
cmd_bytes[1] = 0x02; // 设置为页寻址模式
OLED_WriteCmd(cmd_bytes, 2);
// 显示上半部分
OLED_SetPointer(2 * y, 8 * x); // 设置起始位置(页地址、列地址)
OLED_WriteData(OLED_Font[chr - 32], 8); // 写入上半部分数据
// 显示下半部分
OLED_SetPointer(2 * y + 1, 8 * x); // 设置下半部分起始位置
OLED_WriteData(OLED_Font[chr - 32] + 8, 8); // 写入下半部分数据
}
//显示字符串
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
unsigned char i = 0;
// 遍历字符串,依次显示每个字符
while (str[i] != '\0') {
OLED_ShowChar(x, y, str[i]); // 显示字符
x++; // 列位置右移
// 如果超出一行范围(16列),则退出
if (x >= 16) {
break;
}
i++; // 处理下一个字符
}
}
//显示数字
unsigned long oled_pow(unsigned char m, unsigned char n)
{
unsigned long result = 1;
while (n--) result *= m;
return result;
}
void OLED_ShowNum(unsigned char x, unsigned char y, long num, unsigned char len)
{
unsigned char t, i = 0, temp;
if (num < 0) {
OLED_ShowChar(x, y, '-');
num = -num;
i++;
}
for (t = 0; t < len; t++) {
temp = (num / oled_pow(10, len - t - 1)) % 10;
OLED_ShowChar(x + t + i, y, temp + '0');
}
}
显示中文
unsigned char code Hzk[][32] = {
// 你(0) 好(1) ,(2) 世(3) 界(4) !(5)
{0x00, 0x80, 0x60, 0xF8, 0x07, 0x40, 0x20, 0x18, 0x0F, 0x08, 0xC8, 0x08, 0x08, 0x28, 0x18, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x0C, 0x03, 0x40, 0x80, 0x7F, 0x00, 0x01, 0x06, 0x18, 0x00}, /*"你",0*/
{0x10, 0x10, 0xF0, 0x1F, 0x10, 0xF0, 0x00, 0x80, 0x82, 0x82, 0xE2, 0x92, 0x8A, 0x86, 0x80, 0x00, 0x40, 0x22, 0x15, 0x08, 0x16, 0x61, 0x00, 0x00, 0x40, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"好",1*/
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*",",2*/
{0x20, 0x20, 0x20, 0xFE, 0x20, 0x20, 0xFF, 0x20, 0x20, 0x20, 0xFF, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x47, 0x44, 0x44, 0x44, 0x47, 0x40, 0x40, 0x40, 0x00, 0x00}, /*"世",3*/
{0x00, 0x00, 0x00, 0xFE, 0x92, 0x92, 0x92, 0xFE, 0x92, 0x92, 0x92, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x04, 0x84, 0x62, 0x1E, 0x01, 0x00, 0x01, 0xFE, 0x02, 0x04, 0x04, 0x08, 0x08, 0x00}, /*"界",4*/
{0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!",5*/
};
void main()
{
int i;
OLED_Init();
OLED_Clear();
for (i = 0; i < 6; i++) {
OLED_ShowChinese(i, 0, i, 16); // 第四个参数为字号,需和字模软件中设置的字号一致
}
while (1);
}
//显示中文
void OLED_ShowChinese(unsigned char x, unsigned char y, unsigned char ch, unsigned char size)
{
unsigned char cmd_bytes[2];
// 设置OLED寻址方式
cmd_bytes[0] = 0x20; // 设置寻址模式命令
cmd_bytes[1] = 0x02; // 设置为页寻址模式
OLED_WriteCmd(cmd_bytes, 2);
// 显示上半部分
OLED_SetPointer(2 * y, size * x); // 设置起始位置(页地址、列地址)
OLED_WriteData(Hzk[ch], size); // 写入上半部分数据
// // 显示下半部分
OLED_SetPointer(2 * y + 1, size * x); // 设置下半部分起始位置
OLED_WriteData(Hzk[ch] + size, size); // 写入下半部分数据
}
显示图片
unsigned char code BMP0[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60,
0xE0, 0xE0, 0xE0, 0xE0, 0x60, 0x40, 0x40, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x80, 0xC0, 0xE0,
0x60, 0x20, 0x30, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x30, 0x30, 0x60, 0x60,
0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x38, 0x1C, 0x0C, 0x0C, 0x0C, 0x18, 0xB8, 0xF0, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x03, 0x03, 0x06, 0x0C, 0x1C, 0x38, 0xF0, 0xF0, 0x60, 0x30, 0x31, 0x39, 0x1F,
0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x1C, 0x18, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x03, 0x0F, 0x3F, 0xF3, 0xC2, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x63, 0x77, 0x3E, 0x38, 0x38, 0x18, 0x18,
0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xF8, 0xFC, 0x0E, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0x87, 0x03, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x02, 0x06, 0x0C, 0x18, 0x38, 0x70, 0xE0, 0xC0, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x1F, 0x7F, 0xF8, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1E, 0x3C, 0x70,
0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07,
0x0C, 0x38, 0x70, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0xE0, 0xC0, 0xC0, 0x80,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x03, 0x03, 0x06, 0x0C, 0x18, 0x38, 0x70, 0xE0, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x1E, 0x38, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E,
0x0E, 0x0E, 0x0E, 0x0C, 0x0E, 0x0E, 0x0C, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E, 0x0E, 0x0F, 0x0F,
0x7F, 0x3F, 0x1F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0C, 0x0C, 0x0C, 0x8C, 0xEC, 0xFC, 0x3C, 0x1C, 0x0C,
0x1C, 0x7E, 0x7E, 0x0E, 0x1E, 0x1E, 0x3E, 0x7E, 0x6C, 0x0C, 0x0C, 0x09, 0x0B, 0x0F, 0x0E, 0x0E,
0x0C, 0x18, 0x18, 0x30, 0x30, 0x30, 0x60, 0xE0, 0xE0, 0xE3, 0xFF, 0xBE, 0x8E, 0x8C, 0x8C, 0x8C,
0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x84, 0x84, 0x84, 0x84,
0x84, 0x86, 0x86, 0x86, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x02,
0x02, 0x06, 0x06, 0x06, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x33, 0x3F, 0x0F, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x0F, 0x1F, 0x39, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0x07, 0x0D, 0x19, 0x31, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void main()
{
int i;
OLED_Init();
OLED_Clear();
OLED_ShowImage(0, 0, 128, 64, BMP0); // 字模软件中导入的图片的宽高要和第三个、第四个参数一样
while (1);
}
//显示图片
void OLED_ShowImage(unsigned char x, unsigned char y, unsigned char sizex, unsigned char sizey, unsigned char BMP[])
{
unsigned short j = 0;
unsigned char i, m;
unsigned char cmd_bytes[2];
// 设置OLED寻址方式
cmd_bytes[0] = 0x20; // 设置寻址模式命令
cmd_bytes[1] = 0x02; // 设置为页寻址模式
OLED_WriteCmd(cmd_bytes, 2);
sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
for (i = 0; i < sizey; i++) {
OLED_SetPointer(i, x);
for (m = 0; m < sizex; m++) {
OLED_WriteData(&BMP[j++], 1);
}
}
}
DS1302 时钟
其中涉及到的一些知识点
符号 | 描述 | 说明 | 具体描述 |
---|---|---|---|
VCC2 | 主电源 | 接电源正极 | |
VCC1 | 后备电源 | 接电源正极 | |
X1/X2 | 振荡源 | 外接 32.768KHz 晶振 | |
CE/RST | 复位 | 输入信号,在读、写数据期间,必须为高 | |
I/O | 数据输入/输出 | 见下方 寄存器地址 | |
SCLK | 串行时钟输入 |
寄存器地址
LCD1602 显示实时时间
下方代码是在 LCD1602
基础上添加了 DS1302
时钟实时显示,其余代码在 LCD1602
基础上没有改动。 里面的 LCD_ShowString、LCD_ShowString 可以看上面的扩展方法
sbit RST = P3 ^ 0;
sbit SCLK = P3 ^ 1;
sbit IO = P3 ^ 2;
unsigned char DS1302_Time[] = {30, 31, 18, 4, 12, 24, 3}; // 秒分时日月年星期几
void main()
{
LCD_Init(); // LCD1602 初始化
LCD_ShowString(1, 1, " - - ");
LCD_ShowString(2, 1, " : : ");
while (1) {
read_time();
LCD_ShowNum(1, 1, DS1302_Time[5], 2); // 显示年
LCD_ShowNum(1, 4, DS1302_Time[4], 2); // 显示月
LCD_ShowNum(1, 7, DS1302_Time[3], 2); // 显示日
LCD_ShowNum(2, 1, DS1302_Time[2], 2); // 显示时
LCD_ShowNum(2, 4, DS1302_Time[1], 2); // 显示分
LCD_ShowNum(2, 7, DS1302_Time[0], 2); // 显示秒
}
}
//写数据
void write_ds1302(unsigned char add, unsigned char dat)
{
unsigned char i;
RST = 1; // 把复位线拿高
for (i = 0; i < 8; i++) { // 低位在前
SCLK = 0; // 时钟线拿低开始写数据
IO = add & 0x01;
add >>= 1; // 把地址右移一位
SCLK = 1; // 时钟线拿高
}
for (i = 0; i < 8; i++) {
SCLK = 0; // 时钟线拿低开始写数据
IO = dat & 0x01;
dat >>= 1; // 把数据右移一位
SCLK = 1; // 时钟线拿高
}
RST = 0; // 复位线合低
SCLK = 0;
IO = 0;
}
//读数据
unsigned char read_ds1302(unsigned char add)
{
unsigned char value, i;
RST = 1; // 把复位线拿高
for (i = 0; i < 8; i++) { // 低位在前
SCLK = 0; // 时钟线拿低开始写数据
IO = add & 0x01;
add >>= 1; // 把地址右移一位
SCLK = 1; // 时钟线拿高
}
for (i = 0; i < 8; i++) {
SCLK = 0; // 时钟线拿低开始读数据
value >>= 1;
if (IO == 1)
value |= 0x80;
SCLK = 1; // 时钟线拿高
}
RST = 0; // 复位线合低
SCLK = 0;
IO = 0;
return value; // 返回读出来的数据
}
// BCD码转换为数字
// 返回值为十进制数字
unsigned char datadeal(unsigned char num)
{
return ((num / 16)) * 10 + num % 16;
}
// 数字转换为BCD码
// 返回值为BCD码
unsigned char to_BCD(unsigned char num)
{
return (((num / 10) << 4) | (num % 10));
}
unsigned char code write_add[] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8c, 0x8a}; // 写地址
unsigned char code read_add[] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8d, 0x8b}; // 读地址
// 读取时间
void read_time()
{
DS1302_Time[0] = datadeal(read_ds1302(read_add[0])); // 读秒
DS1302_Time[1] = datadeal(read_ds1302(read_add[1])); // 读分
DS1302_Time[2] = datadeal(read_ds1302(read_add[2])); // 读时
DS1302_Time[3] = datadeal(read_ds1302(read_add[3])); // 读日
DS1302_Time[4] = datadeal(read_ds1302(read_add[4])); // 读月
DS1302_Time[5] = datadeal(read_ds1302(read_add[5])); // 读年
DS1302_Time[6] = datadeal(read_ds1302(read_add[6])); // 读星期
}
//写入时间
void write_time()
{
write_ds1302(0x8e, 0x00); // 打开写保护
write_ds1302(write_add[0], to_BCD(DS1302_Time[0])); // 写秒
write_ds1302(write_add[1], to_BCD(DS1302_Time[1])); // 写分
write_ds1302(write_add[2], to_BCD(DS1302_Time[2])); // 写时
write_ds1302(write_add[3], to_BCD(DS1302_Time[3])); // 写日
write_ds1302(write_add[4], to_BCD(DS1302_Time[4])); // 写月
write_ds1302(write_add[5], to_BCD(DS1302_Time[5])); // 写年
write_ds1302(write_add[6], to_BCD(DS1302_Time[6])); // 写星期
write_ds1302(0x8e, 0x80); // 关闭写保护
}
数码管 显示实时时间
int seg[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
void main()
{
int i;
while (1) {
read_time();
for (i = 0; i < 8; i++) {
P2 = 1 << i;
if (i == 0) {
P0 = seg[DS1302_Time[2] / 10];
} else if (i == 1) {
P0 = seg[DS1302_Time[2] % 10];
} else if (i == 3) {
P0 = seg[DS1302_Time[1] / 10];
} else if (i == 4) {
P0 = seg[DS1302_Time[1] % 10];
} else if (i == 6) {
P0 = seg[DS1302_Time[0] / 10];
} else if (i == 7) {
P0 = seg[DS1302_Time[0] % 10];
} else {
P0 = 0xbf;
}
delay(500);
P0 = 0xff; // 消除拖影
}
}
}
OLED 显示实时时间
下方代码是在 OLED 显示屏
基础上添加了 DS1302
时钟实时显示,其余代码在 OLED 显示屏
基础上没有改动。 OLED_ShowNum,OLED_ShowChinese 方法的实现
unsigned char code date[][32] = {
{0x00, 0x20, 0x18, 0xC7, 0x44, 0x44, 0x44, 0x44, 0xFC, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x04, 0xFF, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, /*"年",0*/
{0x00, 0x00, 0x00, 0xFE, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xFE, 0x00, 0x00, 0x00, 0x80, 0x40, 0x30, 0x0F, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x82, 0x7F, 0x00, 0x00, 0x00}, /*"月",1*/
{0x00, 0x00, 0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xFF, 0x00, 0x00, 0x00, 0x00}, /*"日",2*/
};
void main()
{
OLED_Init();
OLED_Clear();
OLED_ShowChinese(1, 0, 0, 16); // 年
OLED_ShowChinese(3, 0, 1, 16); // 月
OLED_ShowChinese(5, 0, 2, 16); // 日
OLED_ShowChar(2, 1, ':');
OLED_ShowChar(5, 1, ':');
while (1) {
read_time();
OLED_ShowNum(0, 0, DS1302_Time[5], 2); // 年
OLED_ShowNum(4, 0, DS1302_Time[4], 2); // 月
OLED_ShowNum(8, 0, DS1302_Time[3], 2); // 日
OLED_ShowNum(0, 1, DS1302_Time[2], 2); // 时
OLED_ShowNum(3, 1, DS1302_Time[1], 2); // 分
OLED_ShowNum(6, 1, DS1302_Time[0], 2); // 秒
}
}
PWM 波
具体效果可以查看下方的 SG90 舵机
部分。
SG90 舵机
注意
有些舵机只能 正转
,有些只能 反转
,有些 正反转
都可以,不要用错了。舵机的需要的电压范围是 4.8V
~ 6V
,所以遇到舵机不转或者卡主 的情况可能电压不够,需要额外供电,连接一个电池即可。
直流电机
HC05 蓝牙模块
点灯
其余代码和上方的串口通信一样
void main()
{
UsartInit();
while (1) {
if (UartBuf) {
P0 = UartBuf;
}
}
}
连接如下图所示
APP 点灯
等我后面弄个 Android
机再来写