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

c 复制代码
// spi.h
#ifndef __SPI_H
#define __SPI_H

#include "stm32f10x.h"

void SPI2_Init(void);

#endif // __SPI_H

spi.c

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

c 复制代码
// 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

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

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可能有不同的初始化命令序列、地址设置方式和显示参数。

相关推荐
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
PegasusYu5 小时前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
lantiandianzi9 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
文弱书生6569 小时前
输出比较简介
stm32
哔哥哔特商务网9 小时前
高集成的MCU方案已成电机应用趋势?
单片机·嵌入式硬件
跟着杰哥学嵌入式9 小时前
单片机进阶硬件部分_day2_项目实践
单片机·嵌入式硬件
东芝、铠侠总代1361006839311 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
lantiandianzi11 小时前
基于单片机中医药柜管理系统的设计
单片机·嵌入式硬件
嵌入式知识大讲堂11 小时前
HDMI数据传输三种使用场景
单片机
黑客呀12 小时前
[系统安全]Rootkit基础
stm32·单片机·系统安全