请编写一个基于STC89C52RC/LE52RC的矩阵键盘+ OLED显示屏,实现一个计算器的代码,并使这个代码能够正确在keil上运行
时间: 2024-02-05 20:14:05 浏览: 109
以下是基于STC89C52RC/LE52RC的矩阵键盘+ OLED显示屏实现计算器的代码。请将代码复制到Keil中并编译运行。
```
#include <REG52.H>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define KEY P0
sbit SCL = P2^1; // OLED串行时钟线
sbit SDA = P2^0; // OLED串行数据线
sbit CS = P2^2; // OLED片选
uchar code tab[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; // 数码管字符表
uchar num[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; // 数字键值表
uint result = 0; // 计算结果
uint num1 = 0; // 第一个操作数
uint num2 = 0; // 第二个操作数
uchar operator = 0; // 运算符
void delay(uint x) // 延时函数
{
uint i, j;
for (i = x; i > 0; i--)
for (j = 110; j > 0; j--);
}
void I2C_Start() // I2C通信起始信号
{
SDA = 1;
SCL = 1;
_nop_();
_nop_();
_nop_();
SDA = 0;
_nop_();
_nop_();
_nop_();
SCL = 0;
}
void I2C_Stop() // I2C通信停止信号
{
SDA = 0;
SCL = 1;
_nop_();
_nop_();
_nop_();
SDA = 1;
_nop_();
_nop_();
_nop_();
}
void Write_I2C(uchar dat) // I2C通信写数据
{
uchar i;
for (i = 0; i < 8; i++)
{
if (dat & 0x80)
SDA = 1;
else
SDA = 0;
SCL = 1;
_nop_();
_nop_();
_nop_();
SCL = 0;
dat <<= 1;
}
SDA = 1;
SCL = 1;
_nop_();
_nop_();
_nop_();
SCL = 0;
}
void OLED_Init() // OLED初始化
{
I2C_Start();
Write_I2C(0x78); // 写入从机地址
Write_I2C(0x00); // 写入控制字节指令集
Write_I2C(0xAE); // 关闭OLED显示
Write_I2C(0xD5); // 设置时钟分频率
Write_I2C(0x80);
Write_I2C(0xA8); // 设置多路复用
Write_I2C(0x3F); // 1/64duty
Write_I2C(0xD3); // 设置显示偏移量
Write_I2C(0x00);
Write_I2C(0x40); // 设置OLED显示起始行
Write_I2C(0x8D); // 设置电荷泵
Write_I2C(0x14); // 使能电荷泵
Write_I2C(0x20); // 设置内存地址模式
Write_I2C(0x02); // 垂直地址模式
Write_I2C(0xA1); // 设置SEG重映射
Write_I2C(0xC8); // 设置COM重映射
Write_I2C(0xDA); // 设置COM硬件引脚配置
Write_I2C(0x12);
Write_I2C(0x81); // 设置对比度
Write_I2C(0xCF);
Write_I2C(0xD9); // 设置预充电时间
Write_I2C(0xF1);
Write_I2C(0xDB); // 设置VCOMH
Write_I2C(0x40);
Write_I2C(0xA4); // 关闭全局显示
Write_I2C(0xA6); // 设置正常/反向显示
Write_I2C(0xAF); // 开启OLED显示
I2C_Stop();
}
void OLED_Clear() // OLED清屏
{
uchar i, j;
for (i = 0; i < 8; i++)
{
I2C_Start();
Write_I2C(0x78);
Write_I2C(0x00);
Write_I2C(0xb0 + i);
Write_I2C(0x00);
Write_I2C(0x10);
for (j = 0; j < 128; j++)
Write_I2C(0x00);
I2C_Stop();
}
}
void OLED_DisplayNum(uint n) // OLED显示数字
{
uchar i;
uchar buf[5] = {0};
for (i = 0; i < 5; i++)
{
buf[i] = n % 10;
n /= 10;
}
for (i = 0; i < 5; i++)
{
buf[i] = tab[buf[i]];
}
I2C_Start();
Write_I2C(0x78);
Write_I2C(0x00);
Write_I2C(0xb0);
Write_I2C(0x02);
Write_I2C(0x10);
for (i = 4; i >= 1; i--)
{
Write_I2C(buf[i]);
}
Write_I2C(0x00);
I2C_Stop();
}
uchar KeyScan() // 矩阵键盘扫描
{
uchar key_value = 0xff; // 初始化键值为0xff
uchar row, col;
KEY = 0x0f; // 将行线置为低电平
if (KEY != 0x0f) // 判断是否有按键按下
{
delay(10); // 延时去抖
if (KEY != 0x0f) // 再次判断是否有按键按下
{
KEY = 0x0f; // 将行线置为低电平
switch (KEY) // 判断所在列
{
case 0x07: col = 0; break;
case 0x0b: col = 1; break;
case 0x0d: col = 2; break;
case 0x0e: col = 3; break;
default: break;
}
KEY = 0xf0; // 将列线置为低电平
switch (KEY) // 判断所在行
{
case 0x70: row = 0; break;
case 0xb0: row = 1; break;
case 0xd0: row = 2; break;
case 0xe0: row = 3; break;
default: break;
}
key_value = num[row * 4 + col]; // 获取键值
while (KEY != 0xf0); // 等待按键释放
}
}
return key_value; // 返回键值
}
void main()
{
uchar key_value = 0xff;
OLED_Init(); // OLED初始化
OLED_Clear(); // OLED清屏
while (1)
{
key_value = KeyScan(); // 扫描矩阵键盘
if (key_value != 0xff) // 判断是否有按键按下
{
if (key_value <= 9) // 数字键
{
if (operator == 0) // 第一个操作数
num1 = num1 * 10 + key_value;
else // 第二个操作数
num2 = num2 * 10 + key_value;
}
else if (key_value == 0x0a) // 加法键
{
operator = '+';
}
else if (key_value == 0x0b) // 减法键
{
operator = '-';
}
else if (key_value == 0x0c) // 乘法键
{
operator = '*';
}
else if (key_value == 0x0d) // 除法键
{
operator = '/';
}
else if (key_value == 0x0e) // 等于键
{
switch (operator)
{
case '+': result = num1 + num2; break;
case '-': result = num1 - num2; break;
case '*': result = num1 * num2; break;
case '/': result = num1 / num2; break;
default: break;
}
OLED_Clear();
OLED_DisplayNum(result); // 显示计算结果
num1 = 0;
num2 = 0;
operator = 0;
}
}
}
}
```
阅读全文