当前位置: 首页 > article >正文

4.SPI外设—LCD小案例

SPI(Serial Peripheral Interface)是一种常见的同步串行通信协议,用于微控制器和各种外围设备之间的通信。SPI通信通常涉及至少四根线:SCLK(时钟线)、MOSI(主设备数据输出线)、MISO(主设备数据输入线)和CS(从设备选择线)。在与LCD屏幕的通信中,SPI可以用来发送命令和数据。

SPI 知识点

  1. SPI 模式:SPI有四种工作模式,由CPOL和CPHA两个参数决定,它们影响时钟的空闲状态和数据的采样时刻。
  2. 时钟频率:SPI通信的时钟频率可以根据需要设置,但要受到外围设备的限制。
  3. 数据传输:SPI支持全双工通信,可以同时进行数据的发送和接收。
  4. 片选信号:CS信号用于激活特定的SPI设备,低电平有效。

SPI连接LCD案例

以下是一个使用STM32标准外设库连接SPI LCD的详细案例:

  1. 硬件连接

    • LCD VCC 连接 STM32 DC5V/3.3V(电源)
    • LCD GND 连接 STM32 GND(电源地)
    • LCD SDI(MOSI) 连接 STM32 PB15(液晶屏SPI总线数据写信号)
    • LCD SDO(MISO) 连接 STM32 PB14(液晶屏SPI总线数据读信号,如果不使用可以不接线)
    • LCD LED 连接 STM32 PB9(液晶屏背光控制信号,如果不控制可以接5V或3.3V)
    • LCD SCK 连接 STM32 PB13(液晶屏SPI总线时钟信号)
    • LCD DC/RS 连接 STM32 PB10(液晶屏数据/命令控制信号)
    • LCD RST 连接 STM32 PB12(液晶屏复位控制信号)
    • LCD CS 连接 STM32 PB11(液晶屏片选控制信号)
  2. LCD小案例

spi.h

// spi.h
#ifndef __SPI_H
#define __SPI_H

#include "stm32f10x.h"

void SPI2_Init(void);

#endif // __SPI_H

spi.c

// spi.c
#include "spi.h"

void SPI2_Init(void) {
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 使能SPI2和GPIOB的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    
    // 配置SPI2的SCK和MOSI管脚为复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置SPI2的MISO管脚为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // SPI2配置
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI2, &SPI_InitStructure);
    
    // 使能SPI2
    SPI_Cmd(SPI2, ENABLE);
}

lcd.h

// lcd.h
#ifndef __LCD_H
#define __LCD_H

#include "stm32f10x.h"

void LCD_Init(void);
void LCD_SendByte(uint8_t data, uint8_t command);
void LCD_SetCursor(uint8_t x, uint8_t y);
void LCD_WriteString(char *str);

#endif // __LCD_H

lcd.c

// lcd.c
#include "lcd.h"
#include "spi.h"

// 假设DC和CS管脚已经连接到GPIOB的Pin_10和Pin_11
#define LCD_DC_PORT GPIOB
#define LCD_DC_PIN GPIO_Pin_10
#define LCD_CS_PORT GPIOB
#define LCD_CS_PIN GPIO_Pin_11

// 假设LCD的宽度和高度
#define LCD_WIDTH 128
#define LCD_HEIGHT 64

// 假设LCD的命令集
#define LCD_CMD_DISPLAY_ON 0xAF
#define LCD_CMD_CLEAR 0x5C

// 延时函数
void Delay(uint32_t delay_time) {
    // 简单的延时函数,用于LCD初始化
    volatile uint32_t i;
    for (i = 0; i < delay_time * 1000; i++);
}

void LCD_Init(void) {
    // 初始化LCD显示参数
    GPIO_WriteBit(LCD_CS_PORT, LCD_CS_PIN, Bit_SET); // CS高电平,不选中LCD
    GPIO_WriteBit(LCD_DC_PORT, LCD_DC_PIN, Bit_SET); // DC高电平,命令模式

    // 延时,等待LCD准备好
    Delay(100);

    // 发送LCD初始化命令序列
    LCD_SendByte(0xAE, 1); // 关闭显示
    LCD_SendByte(0xD5, 1); // 设置显示时钟频率
    LCD_SendByte(0x50, 1); // 推荐频率
    LCD_SendByte(0xA8, 1); // 设置复用率
    LCD_SendByte(0x3F, 1); // 推荐复用率
    LCD_SendByte(0xD3, 1); // 设置显示偏移
    LCD_SendByte(0x00, 1); // 无偏移
    LCD_SendByte(0x40, 1); // 显示起始行
    LCD_SendByte(0x8D, 1); // 电荷泵设置
    LCD_SendByte(0x14, 1); // 打开电荷泵
    LCD_SendByte(0x20, 1); // 设置内存模式
    LCD_SendByte(0x0C, 1); // 打开通路
    LCD_SendByte(LCD_CMD_DISPLAY_ON, 1); // 打开显示

    // 清除LCD显示
    LCD_SendByte(LCD_CMD_CLEAR, 1);
    Delay(100);
}

void LCD_SendByte(uint8_t data, uint8_t command) {
    // 设置DC和CS管脚的状态
    if (command) {
        // 发送命令
        GPIO_WriteBit(LCD_DC_PORT, LCD_DC_PIN, Bit_SET); // DC高电平,命令模式
    } else {
        // 发送数据
        GPIO_WriteBit(LCD_DC_PORT, LCD_DC_PIN, Bit_RESET); // DC低电平,数据模式
    }
    GPIO_WriteBit(LCD_CS_PORT, LCD_CS_PIN, Bit_RESET); // CS低电平,选中LCD
    
    // 发送数据到SPI
    SPI_I2S_SendData(SPI2, data);
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完毕
    
    // 取消选中LCD
    GPIO_WriteBit(LCD_CS_PORT, LCD_CS_PIN, Bit_SET);
}

void LCD_SetCursor(uint8_t x, uint8_t y) {
    // 设置LCD的光标位置
    LCD_SendByte(0x00, 1); // 设置地址模式
    LCD_SendByte((x >> 4) & 0x0F, 0); // 设置列地址的高两位
    LCD_SendByte(x & 0x0F, 0); // 设置列地址的低两位
    LCD_SendByte(0x10, 1); // 设置页地址
    LCD_SendByte((y >> 4) & 0x0F, 0); // 设置页地址的高两位
    LCD_SendByte(y & 0x0F, 0); // 设置页地址的低两位
}

void LCD_WriteString(char *str) {
    // 写字符串到LCD
    while (*str) {
        LCD_SendByte(*str++, 0); // 0表示数据模式
    }
}

main.c

// main.c
#include "stm32f10x.h"
#include "spi.h"
#include "lcd.h"

int main(void) {
    // 初始化系统
    SystemInit();
    
    // 初始化SPI2
    SPI2_Init();
    
    // 初始化LCD
    LCD_Init();
    
    // 设置光标位置
    LCD_SetCursor(0, 0);
    
    // 显示字符串"你好"
    LCD_WriteString("你好");

    while (1) {
        // 主循环
    }
}

说明!!!!

  1. spi.cspi.h:负责SPI接口的初始化和配置。
  2. lcd.clcd.h:负责LCD的初始化、设置光标位置和写字符串。
  3. main.c:主函数,初始化系统、SPI和LCD,然后显示字符串"你好"。

请注意,这个示例代码假设了LCD的命令集和参数,实际使用时需要根据具体的LCD型号和数据手册进行调整。例如,不同的LCD可能有不同的初始化命令序列、地址设置方式和显示参数。


http://www.kler.cn/a/320760.html

相关文章:

  • 开源科学工程技术软件介绍 – EDA工具KLayout
  • Unity 2022 Nav Mesh 自动寻路入门
  • GRE做题笔记(零散的个人经验)
  • [Android]相关属性功能的裁剪
  • LeetCode 90-子集Ⅱ
  • 容器内的Jenkins使用docker部署服务,服务数据文件挂载问题
  • 拓数派荣获上海数据交易所“数据治理服务商”认证
  • 无线领夹麦克风哪个牌子好,2024年新款领夹麦克风推荐
  • 回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测
  • 【监控体系搭建一】Docker安装与使用
  • 万界星空科技铜拉丝行业MES系统,实现智能化转型
  • Prometheus使用Pushgateway推送数据
  • 【数据结构】栈和队列(Stack Queue)
  • 统信服务器操作系统ade版【iostat】命令详解
  • LeetCode 136. 只出现一次的数字
  • 三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询...)
  • Kafka集群扩容(新增一台kafka节点)
  • Could not load library libcudnn_cnn_train.so.8 问题及(非常简单)解决方案
  • 线阵相机的参数选型计算
  • vue.config.js devServer中changeOrigin的作用
  • VS Code实现flutter多语言(官方推荐Intl)
  • Golang | Leetcode Golang题解之第421题数组中两个数的最大异或值
  • 嵌入式硬件工程师与嵌入式软件工程师的区别(详细版)
  • 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析
  • OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【文件系统】上
  • NLP 序列标注任务核心梳理