【免费开源】stm32串行驱动LCD12864显示正弦函数 波形可视化神器完整项目分享
本项目是一个基于STM32微控制器的LCD12864液晶显示屏驱动程序,通过串行通信方式控制LCD12864显示屏,实现正弦函数波形的实时显示。这个项目将数学函数可视化,让抽象的数学概念变得直观可见,是学习STM32嵌入式开发和图形显示技术的绝佳实践项目。 LCD12864是一款128×64点阵的图形型液晶显示模块,具有体积小、功耗低、显示内容丰富等特点,广泛应用于各种嵌入式系统中。本项目采用串行接口方式驱动LCD12864,相比并行接口方式,可以节省更多的IO引脚资源,非常适合引脚资源有限的STM32微控制器使用。 正弦函数是数学中最基础的周期函数之一,在信号处理、通信系统、音频处理等领域有着广泛的应用。通过在LCD12864上实时显示正弦波形,不仅能够直观地展示正弦函数的周期性特征,还能帮助理解数字信号处理的基本原理。 本项目的核心功能包括:LCD12864的初始化配置、串行通信接口的实现、正弦函数数据的计算与存储、波形绘制算法的实现等。通过这个项目,读者可以深入学习STM32的GPIO、SPI通信、定时器等外设的使用方法,掌握图形显示的基本原理和编程技巧。 直接放到之前写的文章里了,免费开源,下载学习即可。 本项目采用STM32F103系列微控制器作为主控芯片,该系列基于ARM Cortex-M3内核,具有丰富的外设资源和良好的性价比。STM32F103C8T6是最常用的型号,具有64KB Flash存储器、20KB SRAM、48个GPIO引脚,完全满足本项目的需求。 STM32F103的主要特性包括: LCD12864是一款128×64点阵的图形型液晶显示模块,内置ST7920控制器,支持串行和并行两种通信方式。主要技术参数如下: 采用串行接口方式连接STM32和LCD12864,需要以下连接: 软件系统采用模块化设计,主要包含以下模块: LCD12864的串行通信协议采用三线制(CS、SID、SCLK),数据传输时序严格遵循ST7920控制器的规范。以下是LCD12864初始化的核心代码: 正弦函数波形的绘制需要将数学上的连续函数转换为离散的点阵显示。LCD12864的分辨率为128×64,我们需要在这个有限的像素空间内绘制出平滑的正弦波形。 正弦函数的基本公式为:y = A × sin(ωx + φ) + k 其中: 以下是正弦波形绘制的核心代码: 主程序负责系统的初始化和功能协调,通过定时器实现波形的动态刷新,或者通过按键实现不同参数波形的切换。 LCD12864的串行通信采用SPI时序,但与标准SPI有所不同。ST7920控制器定义了特殊的通信协议,每个字节传输需要先发送5个同步字节,然后发送RS位和数据位。这种设计虽然增加了通信开销,但提高了通信的可靠性。 在点阵显示屏上绘制平滑曲线需要采用适当的算法。本项目使用Bresenham直线算法来连接离散的正弦函数点,这种方法计算效率高,适合在资源有限的嵌入式系统中使用。 STM32F103具有硬件浮点运算单元,但为了提高运算效率,在实际应用中可以考虑使用定点数运算代替浮点数运算,或者使用查表法预先计算正弦函数值。 为了提高显示效率,可以建立显示缓冲区,先在内存中完成图形绘制,然后一次性更新到LCD显示屏。这种方法可以减少LCD的访问次数,提高显示速度。 本项目通过STM32驱动LCD12864显示正弦函数波形,展示了嵌入式系统图形显示的基本原理和实现方法。项目涵盖了硬件设计、软件编程、算法实现等多个方面的知识,是学习STM32嵌入式开发的综合性实践项目。 通过本项目的学习,读者可以掌握STM32的GPIO配置、串行通信、定时器使用等基本技能,理解图形显示的原理和方法,为后续更复杂的项目开发打下坚实的基础。项目的代码结构清晰,功能模块化,便于学习和扩展。 项目采用开源方式发布,欢迎广大爱好者学习交流,共同进步。希望这个项目能够帮助更多人了解嵌入式开发的魅力,激发对电子技术的兴趣和热情。【免费开源】stm32串行驱动LCD12864显示正弦函数 波形可视化神器完整项目分享
一、项目概述
源码分享
https://blog.csdn.net/weixin_52908342/article/details/158101046二、系统设计流程图
三、硬件设计
3.1 STM32微控制器选型

3.2 LCD12864液晶显示屏
3.3 硬件连接方案
四、软件设计
4.1 系统架构设计
4.2 LCD12864驱动程序
#include "stm32f10x.h"
#define LCD_CS_PIN GPIO_Pin_0
#define LCD_SID_PIN GPIO_Pin_1
#define LCD_SCLK_PIN GPIO_Pin_2
#define LCD_RST_PIN GPIO_Pin_3
#define LCD_PORT GPIOA
void LCD_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = LCD_CS_PIN | LCD_SID_PIN | LCD_SCLK_PIN | LCD_RST_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LCD_PORT, &GPIO_InitStructure);
GPIO_SetBits(LCD_PORT, LCD_CS_PIN);
GPIO_SetBits(LCD_PORT, LCD_SID_PIN);
GPIO_SetBits(LCD_PORT, LCD_SCLK_PIN);
GPIO_SetBits(LCD_PORT, LCD_RST_PIN);
}
void LCD_WriteByte(uint8_t data, uint8_t rs)
{
uint8_t i;
uint8_t temp;
GPIO_ResetBits(LCD_PORT, LCD_CS_PIN);
for(i = 0; i < 5; i++) {
GPIO_ResetBits(LCD_PORT, LCD_SCLK_PIN);
GPIO_SetBits(LCD_PORT, LCD_SID_PIN);
GPIO_SetBits(LCD_PORT, LCD_SCLK_PIN);
}
GPIO_ResetBits(LCD_PORT, LCD_SCLK_PIN);
if(rs) GPIO_SetBits(LCD_PORT, LCD_SID_PIN);
else GPIO_ResetBits(LCD_PORT, LCD_SID_PIN);
GPIO_SetBits(LCD_PORT, LCD_SCLK_PIN);
GPIO_ResetBits(LCD_PORT, LCD_SCLK_PIN);
GPIO_SetBits(LCD_PORT, LCD_SID_PIN);
GPIO_SetBits(LCD_PORT, LCD_SCLK_PIN);
for(i = 0; i < 4; i++) {
temp = data;
temp = temp << i;
temp = temp & 0x80;
GPIO_ResetBits(LCD_PORT, LCD_SCLK_PIN);
if(temp) GPIO_SetBits(LCD_PORT, LCD_SID_PIN);
else GPIO_ResetBits(LCD_PORT, LCD_SID_PIN);
GPIO_SetBits(LCD_PORT, LCD_SCLK_PIN);
}
for(i = 4; i < 8; i++) {
temp = data;
temp = temp << i;
temp = temp & 0x80;
GPIO_ResetBits(LCD_PORT, LCD_SCLK_PIN);
if(temp) GPIO_SetBits(LCD_PORT, LCD_SID_PIN);
else GPIO_ResetBits(LCD_PORT, LCD_SID_PIN);
GPIO_SetBits(LCD_PORT, LCD_SCLK_PIN);
}
GPIO_SetBits(LCD_PORT, LCD_CS_PIN);
}
void LCD_WriteCommand(uint8_t cmd)
{
LCD_WriteByte(0xf8, 0);
LCD_WriteByte(cmd & 0xf0, 1);
LCD_WriteByte((cmd << 4) & 0xf0, 1);
}
void LCD_WriteData(uint8_t data)
{
LCD_WriteByte(0xfa, 0);
LCD_WriteByte(data & 0xf0, 1);
LCD_WriteByte((data << 4) & 0xf0, 1);
}
void LCD_Init(void)
{
LCD_GPIO_Init();
GPIO_ResetBits(LCD_PORT, LCD_RST_PIN);
Delay_ms(10);
GPIO_SetBits(LCD_PORT, LCD_RST_PIN);
Delay_ms(10);
LCD_WriteCommand(0x30);
Delay_ms(5);
LCD_WriteCommand(0x30);
Delay_ms(5);
LCD_WriteCommand(0x0c);
Delay_ms(5);
LCD_WriteCommand(0x01);
Delay_ms(5);
LCD_WriteCommand(0x06);
Delay_ms(5);
}
void LCD_Clear(void)
{
LCD_WriteCommand(0x30);
LCD_WriteCommand(0x01);
Delay_ms(10);
}4.3 正弦函数波形绘制
#include <math.h>
#define PI 3.14159265358979323846
#define LCD_WIDTH 128
#define LCD_HEIGHT 64
void LCD_DrawPoint(uint8_t x, uint8_t y)
{
uint8_t x_addr, y_addr;
uint8_t bit_data;
if(x >= LCD_WIDTH || y >= LCD_HEIGHT) return;
y_addr = y / 8;
bit_data = 0x01 << (y % 8);
LCD_WriteCommand(0x80 | y_addr);
LCD_WriteCommand(0x80 | x);
LCD_WriteData(bit_data);
}
void LCD_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
{
int dx, dy, sx, sy, err, e2;
dx = abs(x2 - x1);
dy = abs(y2 - y1);
if(x1 < x2) sx = 1;
else sx = -1;
if(y1 < y2) sy = 1;
else sy = -1;
err = dx - dy;
while(1) {
LCD_DrawPoint(x1, y1);
if(x1 == x2 && y1 == y2) break;
e2 = 2 * err;
if(e2 > -dy) {
err -= dy;
x1 += sx;
}
if(e2 < dx) {
err += dx;
y1 += sy;
}
}
}
void LCD_DrawSineWave(void)
{
uint8_t x, y;
float angle;
float amplitude = 25.0;
float frequency = 2.0;
float offset = 32.0;
LCD_Clear();
LCD_WriteCommand(0x34);
LCD_WriteCommand(0x36);
for(x = 0; x < LCD_WIDTH; x++) {
angle = (float)x * frequency * 2.0 * PI / LCD_WIDTH;
y = (uint8_t)(offset + amplitude * sin(angle));
LCD_DrawPoint(x, y);
if(x > 0) {
uint8_t prev_x = x - 1;
float prev_angle = (float)prev_x * frequency * 2.0 * PI / LCD_WIDTH;
uint8_t prev_y = (uint8_t)(offset + amplitude * sin(prev_angle));
LCD_DrawLine(prev_x, prev_y, x, y);
}
}
LCD_WriteCommand(0x30);
}
void LCD_DisplayText(uint8_t x, uint8_t y, char *str)
{
LCD_WriteCommand(0x80 | y);
LCD_WriteCommand(0x80 | x);
while(*str != '\0') {
LCD_WriteData(*str);
str++;
}
}4.4 主程序设计
int main(void)
{
SystemInit();
LCD_Init();
LCD_Clear();
LCD_DisplayText(0, 0, "Sine Wave Demo");
Delay_ms(1000);
LCD_DrawSineWave();
LCD_DisplayText(0, 2, "y=A*sin(wx+phi)+k");
LCD_DisplayText(0, 4, "A=25, w=2, phi=0");
LCD_DisplayText(0, 6, "k=32");
while(1) {
Delay_ms(1000);
}
}
void Delay_ms(uint32_t ms)
{
uint32_t i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 9000; j++);
}五、关键技术点分析
5.1 串行通信时序
5.2 图形绘制算法
5.3 浮点数运算优化
5.4 显示缓冲区管理
六、项目扩展与应用
6.1 功能扩展
6.2 应用场景
七、总结
八、参考资料
