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

相关推荐
hairenjing11236 小时前
使用 Mac 数据恢复从 iPhoto 图库中恢复照片
windows·stm32·嵌入式硬件·macos·word
IT B业生8 小时前
51单片机教程(六)- LED流水灯
单片机·嵌入式硬件·51单片机
一枝小雨8 小时前
51单片机学习心得2(基于STC89C52):串口通信(UART)
单片机·嵌入式硬件·51单片机
IT B业生9 小时前
51单片机教程(一)- 开发环境搭建
单片机·嵌入式硬件·51单片机
u01015265810 小时前
STM32F103C8T6学习笔记2--LED流水灯与蜂鸣器
笔记·stm32·学习
海绵波波10711 小时前
Webserver(4.8)UDP、广播、组播
单片机·网络协议·udp
好想有猫猫11 小时前
【51单片机】串口通信原理 + 使用
c语言·单片机·嵌入式硬件·51单片机·1024程序员节
stm 学习ing13 小时前
C语言 循环高级
c语言·开发语言·单片机·嵌入式硬件·算法·嵌入式实时数据库
w微信1501350781213 小时前
小华一级 代理商 HC32F005C6PA-TSSOP20 HC32F005系列
c语言·arm开发·单片机·嵌入式硬件
北京迅为14 小时前
【北京迅为】《STM32MP157开发板嵌入式开发指南》-第七十八章 Qt控制硬件
linux·stm32·单片机·嵌入式硬件