467 lines
11 KiB
C
467 lines
11 KiB
C
#include "iic.h"
|
||
#include "stm32f10x.h"
|
||
|
||
|
||
#include <stdint.h>
|
||
|
||
|
||
|
||
|
||
|
||
const uint8_t Font6x8[][6] = {
|
||
// SPACE (0x20)
|
||
{0x00,0x00,0x00,0x00,0x00,0x00}, // ' '
|
||
{0x00,0x00,0x5F,0x00,0x00,0x00}, // '!'
|
||
{0x00,0x07,0x00,0x07,0x00,0x00}, // '"'
|
||
{0x14,0x7F,0x14,0x7F,0x14,0x00}, // '#'
|
||
{0x24,0x2A,0x7F,0x2A,0x12,0x00}, // '$'
|
||
{0x23,0x13,0x08,0x64,0x62,0x00}, // '%'
|
||
{0x36,0x49,0x55,0x22,0x50,0x00}, // '&'
|
||
{0x00,0x05,0x03,0x00,0x00,0x00}, // '''
|
||
{0x00,0x1C,0x22,0x41,0x00,0x00}, // '('
|
||
{0x00,0x41,0x22,0x1C,0x00,0x00}, // ')'
|
||
{0x14,0x08,0x3E,0x08,0x14,0x00}, // '*'
|
||
{0x08,0x08,0x3E,0x08,0x08,0x00}, // '+'
|
||
{0x00,0x50,0x30,0x00,0x00,0x00}, // ','
|
||
{0x08,0x08,0x08,0x08,0x08,0x00}, // '-'
|
||
{0x00,0x60,0x60,0x00,0x00,0x00}, // '.'
|
||
{0x20,0x10,0x08,0x04,0x02,0x00}, // '/'
|
||
|
||
{0x3E,0x51,0x49,0x45,0x3E,0x00}, // '0' (0x30)
|
||
{0x00,0x42,0x7F,0x40,0x00,0x00}, // '1'
|
||
{0x42,0x61,0x51,0x49,0x46,0x00}, // '2'
|
||
{0x21,0x41,0x45,0x4B,0x31,0x00}, // '3'
|
||
{0x18,0x14,0x12,0x7F,0x10,0x00}, // '4'
|
||
{0x27,0x45,0x45,0x45,0x39,0x00}, // '5'
|
||
{0x3C,0x4A,0x49,0x49,0x30,0x00}, // '6'
|
||
{0x01,0x71,0x09,0x05,0x03,0x00}, // '7'
|
||
{0x36,0x49,0x49,0x49,0x36,0x00}, // '8'
|
||
{0x06,0x49,0x49,0x29,0x1E,0x00}, // '9'
|
||
|
||
{0x00,0x36,0x36,0x00,0x00,0x00}, // ':' (0x3A)
|
||
{0x00,0x56,0x36,0x00,0x00,0x00}, // ';'
|
||
{0x08,0x14,0x22,0x41,0x00,0x00}, // '<'
|
||
{0x14,0x14,0x14,0x14,0x14,0x00}, // '='
|
||
{0x00,0x41,0x22,0x14,0x08,0x00}, // '>'
|
||
{0x02,0x01,0x51,0x09,0x06,0x00}, // '?'
|
||
|
||
{0x32,0x49,0x79,0x41,0x3E,0x00}, // '@' (0x40)
|
||
{0x7E,0x11,0x11,0x11,0x7E,0x00}, // 'A'
|
||
{0x7F,0x49,0x49,0x49,0x36,0x00}, // 'B'
|
||
{0x3E,0x41,0x41,0x41,0x22,0x00}, // 'C'
|
||
{0x7F,0x41,0x41,0x22,0x1C,0x00}, // 'D'
|
||
{0x7F,0x49,0x49,0x49,0x41,0x00}, // 'E'
|
||
{0x7F,0x09,0x09,0x09,0x01,0x00}, // 'F'
|
||
{0x3E,0x41,0x49,0x49,0x7A,0x00}, // 'G'
|
||
{0x7F,0x08,0x08,0x08,0x7F,0x00}, // 'H'
|
||
{0x00,0x41,0x7F,0x41,0x00,0x00}, // 'I'
|
||
{0x20,0x40,0x41,0x3F,0x01,0x00}, // 'J'
|
||
{0x7F,0x08,0x14,0x22,0x41,0x00}, // 'K'
|
||
{0x7F,0x40,0x40,0x40,0x40,0x00}, // 'L'
|
||
{0x7F,0x02,0x0C,0x02,0x7F,0x00}, // 'M'
|
||
{0x7F,0x04,0x08,0x10,0x7F,0x00}, // 'N'
|
||
{0x3E,0x41,0x41,0x41,0x3E,0x00}, // 'O'
|
||
|
||
{0x7F,0x09,0x09,0x09,0x06,0x00}, // 'P' (0x50)
|
||
{0x3E,0x41,0x51,0x21,0x5E,0x00}, // 'Q'
|
||
{0x7F,0x09,0x19,0x29,0x46,0x00}, // 'R'
|
||
{0x46,0x49,0x49,0x49,0x31,0x00}, // 'S'
|
||
{0x01,0x01,0x7F,0x01,0x01,0x00}, // 'T'
|
||
{0x3F,0x40,0x40,0x40,0x3F,0x00}, // 'U'
|
||
{0x1F,0x20,0x40,0x20,0x1F,0x00}, // 'V'
|
||
{0x3F,0x40,0x38,0x40,0x3F,0x00}, // 'W'
|
||
{0x63,0x14,0x08,0x14,0x63,0x00}, // 'X'
|
||
{0x07,0x08,0x70,0x08,0x07,0x00}, // 'Y'
|
||
{0x61,0x51,0x49,0x45,0x43,0x00}, // 'Z'
|
||
|
||
{0x00,0x7F,0x41,0x41,0x00,0x00}, // '['
|
||
{0x02,0x04,0x08,0x10,0x20,0x00}, // '\'
|
||
{0x00,0x41,0x41,0x7F,0x00,0x00}, // ']'
|
||
{0x04,0x02,0x01,0x02,0x04,0x00}, // '^'
|
||
{0x80,0x80,0x80,0x80,0x80,0x00}, // '_'
|
||
{0x00,0x03,0x05,0x00,0x00,0x00}, // '`'
|
||
|
||
{0x20,0x54,0x54,0x54,0x78,0x00}, // 'a' (0x61)
|
||
{0x7F,0x48,0x44,0x44,0x38,0x00}, // 'b'
|
||
{0x38,0x44,0x44,0x44,0x20,0x00}, // 'c'
|
||
{0x38,0x44,0x44,0x48,0x7F,0x00}, // 'd'
|
||
{0x38,0x54,0x54,0x54,0x18,0x00}, // 'e'
|
||
{0x08,0x7E,0x09,0x01,0x02,0x00}, // 'f'
|
||
{0x0C,0x52,0x52,0x52,0x3E,0x00}, // 'g'
|
||
{0x7F,0x08,0x04,0x04,0x78,0x00}, // 'h'
|
||
{0x00,0x44,0x7D,0x40,0x00,0x00}, // 'i'
|
||
{0x20,0x40,0x44,0x3D,0x00,0x00}, // 'j'
|
||
{0x7F,0x10,0x28,0x44,0x00,0x00}, // 'k'
|
||
{0x00,0x41,0x7F,0x40,0x00,0x00}, // 'l'
|
||
{0x7C,0x04,0x18,0x04,0x78,0x00}, // 'm'
|
||
{0x7C,0x08,0x04,0x04,0x78,0x00}, // 'n'
|
||
{0x38,0x44,0x44,0x44,0x38,0x00}, // 'o'
|
||
|
||
{0x7C,0x14,0x14,0x14,0x08,0x00}, // 'p' (0x70)
|
||
{0x08,0x14,0x14,0x18,0x7C,0x00}, // 'q'
|
||
{0x7C,0x08,0x04,0x04,0x08,0x00}, // 'r'
|
||
{0x48,0x54,0x54,0x54,0x20,0x00}, // 's'
|
||
{0x04,0x3F,0x44,0x40,0x20,0x00}, // 't'
|
||
{0x3C,0x40,0x40,0x20,0x7C,0x00}, // 'u'
|
||
{0x1C,0x20,0x40,0x20,0x1C,0x00}, // 'v'
|
||
{0x3C,0x40,0x30,0x40,0x3C,0x00}, // 'w'
|
||
{0x44,0x28,0x10,0x28,0x44,0x00}, // 'x'
|
||
{0x0C,0x50,0x50,0x50,0x3C,0x00}, // 'y'
|
||
{0x44,0x64,0x54,0x4C,0x44,0x00}, // 'z'
|
||
|
||
{0x08,0x36,0x41,0x00,0x00,0x00}, // '{'
|
||
{0x00,0x00,0x7F,0x00,0x00,0x00}, // '|'
|
||
{0x00,0x41,0x36,0x08,0x00,0x00}, // '}'
|
||
{0x02,0x01,0x02,0x04,0x02,0x00}, // '~'
|
||
};
|
||
|
||
#define OLED_WIDTH 128
|
||
#define OLED_HEIGHT 64
|
||
|
||
// OLED 显存,1bit 表示一个像素(黑白屏)
|
||
// 128 * 64 / 8 = 1024 字节
|
||
uint8_t OLED_GRAM[8][128]; // 8页,每页8行,共64行
|
||
|
||
#define SDA_PIN GPIO_Pin_8
|
||
#define SCL_PIN GPIO_Pin_9
|
||
#define I2C_PORT GPIOB
|
||
|
||
#define SDA_HIGH() GPIO_SetBits(I2C_PORT, SDA_PIN)
|
||
#define SDA_LOW() GPIO_ResetBits(I2C_PORT, SDA_PIN)
|
||
#define SCL_HIGH() GPIO_SetBits(I2C_PORT, SCL_PIN)
|
||
#define SCL_LOW() GPIO_ResetBits(I2C_PORT, SCL_PIN)
|
||
|
||
#define READ_SDA() GPIO_ReadInputDataBit(I2C_PORT, SDA_PIN)
|
||
|
||
|
||
void delay(){
|
||
__NOP();
|
||
|
||
}
|
||
|
||
void delay_us_simple(uint32_t us)
|
||
{
|
||
uint32_t i;
|
||
while(us--)
|
||
{
|
||
for(i = 0; i < 8; i++); // 简单调整这个数字以匹配频率
|
||
}
|
||
}
|
||
|
||
void delay_ms_simple(uint32_t ms)
|
||
{
|
||
while(ms--)
|
||
{
|
||
delay_us_simple(1000); // 1000 微秒 = 1 毫秒
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void IIC_GPIO_Init(void)
|
||
{
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||
|
||
GPIO_InitTypeDef GPIO_InitStructure;
|
||
GPIO_InitStructure.GPIO_Pin = SDA_PIN | SCL_PIN;
|
||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // ????
|
||
GPIO_Init(I2C_PORT, &GPIO_InitStructure);
|
||
|
||
SDA_HIGH();
|
||
SCL_HIGH();
|
||
}
|
||
|
||
|
||
void IIC_Delay(void)
|
||
{
|
||
//delay(1); // 5us 延时,100kHz I2C
|
||
}
|
||
|
||
void IIC_Start(void)
|
||
{
|
||
SDA_HIGH();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
SDA_LOW();
|
||
IIC_Delay();
|
||
SCL_LOW();
|
||
IIC_Delay();
|
||
}
|
||
|
||
void IIC_Stop(void)
|
||
{
|
||
SDA_LOW();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
SDA_HIGH();
|
||
IIC_Delay();
|
||
}
|
||
|
||
void IIC_Send_Byte(uint8_t data)
|
||
{
|
||
for (int i = 0; i < 8; i++) {
|
||
if (data & 0x80)
|
||
SDA_HIGH();
|
||
else
|
||
SDA_LOW();
|
||
data <<= 1;
|
||
|
||
IIC_Delay();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
SCL_LOW();
|
||
IIC_Delay();
|
||
}
|
||
}
|
||
|
||
uint8_t IIC_Read_Byte(uint8_t ack)
|
||
{
|
||
uint8_t data = 0;
|
||
|
||
SDA_HIGH(); // 释放 SDA
|
||
|
||
for (int i = 0; i < 8; i++) {
|
||
data <<= 1;
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
if (READ_SDA()) data |= 1;
|
||
SCL_LOW();
|
||
IIC_Delay();
|
||
}
|
||
|
||
// 发送 ACK 或 NACK
|
||
if (ack)
|
||
SDA_LOW();
|
||
else
|
||
SDA_HIGH();
|
||
|
||
IIC_Delay();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
SCL_LOW();
|
||
SDA_HIGH(); // 释放 SDA
|
||
|
||
return data;
|
||
}
|
||
|
||
uint8_t IIC_Wait_Ack(void)
|
||
{
|
||
uint8_t timeout = 0;
|
||
|
||
SDA_HIGH(); // 释放 SDA
|
||
IIC_Delay();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
|
||
while (READ_SDA()) {
|
||
timeout++;
|
||
if (timeout > 250) {
|
||
IIC_Stop();
|
||
return 1; // 失败
|
||
}
|
||
}
|
||
|
||
SCL_LOW();
|
||
return 0; // 成功
|
||
}
|
||
|
||
void IIC_Ack(void)
|
||
{
|
||
SDA_LOW();
|
||
IIC_Delay();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
SCL_LOW();
|
||
SDA_HIGH();
|
||
}
|
||
|
||
void IIC_NAck(void)
|
||
{
|
||
SDA_HIGH();
|
||
IIC_Delay();
|
||
SCL_HIGH();
|
||
IIC_Delay();
|
||
SCL_LOW();
|
||
}
|
||
|
||
|
||
void OLED_WriteCommand(uint8_t cmd)
|
||
{
|
||
IIC_Start();
|
||
IIC_Send_Byte(0x78); // I2C 地址
|
||
IIC_Wait_Ack();
|
||
IIC_Send_Byte(0x00); // 写命令
|
||
IIC_Wait_Ack();
|
||
IIC_Send_Byte(cmd);
|
||
IIC_Wait_Ack();
|
||
IIC_Stop();
|
||
}
|
||
|
||
void OLED_WriteData(uint8_t data)
|
||
{
|
||
IIC_Start();
|
||
IIC_Send_Byte(0x78);
|
||
IIC_Wait_Ack();
|
||
IIC_Send_Byte(0x40); // 写数据
|
||
IIC_Wait_Ack();
|
||
IIC_Send_Byte(data);
|
||
IIC_Wait_Ack();
|
||
IIC_Stop();
|
||
}
|
||
|
||
|
||
|
||
void OLED_Fill(uint8_t data)
|
||
{
|
||
for(uint8_t page = 0; page < 8; page++)
|
||
{
|
||
OLED_WriteCommand(0xB0 + page); // 页地址
|
||
OLED_WriteCommand(0x00); // 列低地址
|
||
OLED_WriteCommand(0x10); // 列高地址
|
||
|
||
for(uint8_t col = 0; col < 128; col++)
|
||
{
|
||
OLED_WriteData(data);
|
||
}
|
||
}
|
||
}
|
||
|
||
void OLED_Init(void)
|
||
{
|
||
delay_ms_simple(100); // 等待 OLED 上电稳定
|
||
|
||
OLED_WriteCommand(0xAE); // 关闭显示
|
||
|
||
OLED_WriteCommand(0x20); // 设置内存地址模式
|
||
OLED_WriteCommand(0x10); // 00,水平地址模式; 01,垂直地址模式; 10,页地址模式(默认)
|
||
|
||
OLED_WriteCommand(0xB0); // 设置页起始地址(0~7)
|
||
|
||
OLED_WriteCommand(0xC8); // COM输出扫描方向:从 COM[N-1] 到 COM0
|
||
|
||
OLED_WriteCommand(0x00); // 设置低列起始地址
|
||
OLED_WriteCommand(0x10); // 设置高列起始地址
|
||
|
||
OLED_WriteCommand(0x40); // 设置起始行地址(0~63)
|
||
|
||
OLED_WriteCommand(0x81); // 对比度设置
|
||
OLED_WriteCommand(0xFF); // 对比度值(0x00~0xFF)
|
||
|
||
OLED_WriteCommand(0xA1); // 段重映射:正常(A0),反转(A1)
|
||
|
||
OLED_WriteCommand(0xA6); // 显示正常(A6),反相显示(A7)
|
||
|
||
OLED_WriteCommand(0xA8); // 多路复用率
|
||
OLED_WriteCommand(0x3F); // 1/64 duty(0x3F)
|
||
|
||
OLED_WriteCommand(0xA4); // 全局显示开启,输出跟随 RAM 内容
|
||
|
||
OLED_WriteCommand(0xD3); // 设置显示偏移
|
||
OLED_WriteCommand(0x00); // 无偏移
|
||
|
||
OLED_WriteCommand(0xD5); // 设置显示时钟分频比/振荡器频率
|
||
OLED_WriteCommand(0x80); // 推荐值
|
||
|
||
OLED_WriteCommand(0xD9); // 设置预充电周期
|
||
OLED_WriteCommand(0xF1); // 推荐值
|
||
|
||
OLED_WriteCommand(0xDA); // 设置 COM 引脚配置
|
||
OLED_WriteCommand(0x12);
|
||
|
||
OLED_WriteCommand(0xDB); // 设置 VCOMH 电压倍率
|
||
OLED_WriteCommand(0x40); // 推荐值
|
||
|
||
OLED_WriteCommand(0x8D); // 使能电荷泵
|
||
OLED_WriteCommand(0x14); // 开启
|
||
|
||
OLED_WriteCommand(0xAF); // 开启显示
|
||
|
||
OLED_Fill(0xFF); // 清屏
|
||
}
|
||
|
||
void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color) {
|
||
if (x >= OLED_WIDTH || y >= OLED_HEIGHT) return;
|
||
|
||
if (color)
|
||
OLED_GRAM[y / 8][x] |= (1 << (y % 8));
|
||
else
|
||
OLED_GRAM[y / 8][x] &= ~(1 << (y % 8));
|
||
}
|
||
|
||
|
||
|
||
void OLED_Refresh(void) {
|
||
for (uint8_t page = 0; page < 8; page++) {
|
||
OLED_WriteCommand(0xB0 + page); // 设置页地址
|
||
OLED_WriteCommand(0x00); // 设置低列地址
|
||
OLED_WriteCommand(0x10); // 设置高列地址
|
||
|
||
for (uint8_t col = 0; col < OLED_WIDTH; col++) {
|
||
OLED_WriteData(OLED_GRAM[page][col]);
|
||
}
|
||
}
|
||
}
|
||
void OLED_ShowChar(uint8_t x, uint8_t y, char chr) {
|
||
if (x > OLED_WIDTH - 6 || y > 7) return;
|
||
|
||
uint8_t c = chr - 32; // ASCII偏移
|
||
for (uint8_t i = 0; i < 6; i++) {
|
||
OLED_GRAM[y][x + i] = Font6x8[c][i];
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
void lcd_show_all_ascii_lowercase() {
|
||
uint16_t x = 0, y = 0;
|
||
char ch = 'a';
|
||
|
||
for (int row = 0; row < 10; row++) {
|
||
for (int col = 0; col < 16; col++) {
|
||
OLED_ShowChar(x, y, ch); // 白色
|
||
x += 8;
|
||
ch++;
|
||
if (ch > 'z') ch = 'a'; // 循环 a-z
|
||
}
|
||
x = 0;
|
||
y += 16;
|
||
}
|
||
}
|
||
|
||
void test(){
|
||
|
||
|
||
|
||
|
||
IIC_GPIO_Init();
|
||
|
||
OLED_Init();
|
||
|
||
lcd_show_all_ascii_lowercase();
|
||
|
||
OLED_Refresh();
|
||
|
||
while(1){
|
||
|
||
//OLED_Fill(0xFF); // 清屏
|
||
//delay_ms_simple(1000);
|
||
|
||
//OLED_Fill(0x00);
|
||
//delay_ms_simple(1000);
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|