源代码,基于STM32F103的多种外围芯片驱动程序,集成在一个项目中,采用Keil开发,方便调试 EEPROM/FRAM : AT24Cxx (ATMEL ,I2C 接口) EEPROM: ST25AAXX (ST ,SPI 接口) ADC: AD7684( ADI ,3线SPI接口) 步进电机驱动 : TMC2660 (TRINAMIC ,SPI 接口) DAC: AD5290(ADI ,3线SPI 接口) \\t 热电阻/热电偶驱动芯片: AD7793 (ADI,SPI 接口)

在嵌入式开发领域,基于STM32F103系列的芯片广泛应用于各类项目中。今天跟大家分享一个将多种外围芯片驱动集成在一个项目中的经历,开发环境选用Keil,它在调试方面具有很大优势。

一、项目概述

本项目集成了多种不同类型的外围芯片驱动,涵盖存储、模数转换、电机驱动等多个功能领域,旨在打造一个多功能的嵌入式系统基础框架。

二、各芯片驱动实现

(一)EEPROM/FRAM - AT24Cxx(I2C接口)

AT24Cxx是一款基于I2C接口的EEPROM/FRAM芯片。I2C协议是一种两线式串行总线,通过SCL(时钟线)和SDA(数据线)进行通信。

在Keil中,我们首先要初始化I2C外设。以下是简单的初始化代码片段:

void I2C_Init(void) {
    // 使能I2C和GPIO时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef I2C_InitStruct;

    // 配置SCL和SDA引脚为复用推挽输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 连接引脚到I2C外设
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_I2C1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_I2C1);

    // I2C初始化
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStruct.I2C_ClockSpeed = 100000;
    I2C_Init(I2C1, &I2C_InitStruct);

    // 使能I2C
    I2C_Cmd(I2C1, ENABLE);
}

分析:这段代码首先使能了I2C和相关GPIO的时钟,接着配置SCL和SDA引脚为复用推挽输出模式,并连接到I2C外设。然后对I2C进行初始化设置,包括工作模式、时钟速度等,最后使能I2C外设。

(二)EEPROM - ST25AAXX(SPI接口)

SPI协议相对I2C更为简单,它通过四条线(SCK、MOSI、MISO、NSS)进行通信。以下是SPI初始化代码:

void SPI_Init(void) {
    // 使能SPI和GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct;
    SPI_InitTypeDef SPI_InitStruct;

    // 配置SCK、MOSI引脚为复用推挽输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 配置MISO引脚为浮空输入
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // SPI初始化
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &SPI_InitStruct);

    // 使能SPI
    SPI_Cmd(SPI1, ENABLE);
}

分析:这里先使能SPI和GPIO时钟,然后分别配置SCK、MOSI为复用推挽输出,MISO为浮空输入。SPI初始化设置包括主从模式、数据大小、时钟极性等,最后使能SPI。

(三)ADC - AD7684(3线SPI接口)

AD7684模数转换芯片采用3线SPI接口。在代码实现上,与普通SPI类似,但要注意其特定的通信时序和寄存器配置。

uint16_t AD7684_Read(void) {
    uint16_t data;
    // 拉低片选
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送读取命令
    SPI_I2S_SendData(SPI1, 0x01);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    SPI_I2S_ReceiveData(SPI1);

    // 读取数据
    SPI_I2S_SendData(SPI1, 0x00);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    data = SPI_I2S_ReceiveData(SPI1);

    // 拉高片选
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
    return data;
}

分析:此函数首先拉低片选,发送读取命令并丢弃第一个返回值(可能为无效数据),然后再次发送数据以读取转换后的结果,最后拉高片选,返回读取到的数据。

(四)步进电机驱动 - TMC2660(SPI接口)

TMC2660用于步进电机驱动,通过SPI接口进行配置和控制。

void TMC2660_Write(uint8_t address, uint32_t data) {
    // 拉低片选
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送地址和数据
    SPI_I2S_SendData(SPI1, address);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, (data >> 16) & 0xFF);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, (data >> 8) & 0xFF);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, data & 0xFF);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

    // 拉高片选
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

分析:该函数用于向TMC2660写入配置数据,先拉低片选,然后依次发送地址和32位数据的各个字节,最后拉高片选完成操作。

(五)DAC - AD5290(3线SPI接口)

AD5290是一款数模转换芯片,通过3线SPI接口控制。

void AD5290_SetValue(uint8_t value) {
    // 拉低片选
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送设置值
    SPI_I2S_SendData(SPI1, value);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

    // 拉高片选
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

分析:函数通过拉低片选,发送设置值,然后拉高片选,完成对AD5290输出值的设置。

(六)热电阻/热电偶驱动芯片 - AD7793(SPI接口)

AD7793用于热电阻和热电偶的驱动,SPI通信同样是关键。

void AD7793_Write(uint8_t command) {
    // 拉低片选
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送命令
    SPI_I2S_SendData(SPI1, command);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

    // 拉高片选
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

uint16_t AD7793_Read(void) {
    uint16_t data;
    // 拉低片选
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送读取命令
    SPI_I2S_SendData(SPI1, 0x01);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    SPI_I2S_ReceiveData(SPI1);

    // 读取数据
    SPI_I2S_SendData(SPI1, 0x00);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    data = SPI_I2S_ReceiveData(SPI1);

    // 拉高片选
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
    return data;
}

分析:这两个函数分别用于向AD7793写入命令和读取数据,流程与AD7684类似,都是通过片选控制和SPI通信来完成操作。

三、Keil调试优势

Keil提供了直观的调试界面,在调试多芯片驱动项目时,可以方便地设置断点,观察各芯片相关寄存器的值,监测SPI或I2C总线上的数据传输。例如,在ADC读取函数中设置断点,就能实时看到每次转换后的数据是否正确。同时,通过Keil的波形分析功能,还能直观地查看SPI时钟、数据信号的时序是否符合要求。

将多种外围芯片驱动集成在基于STM32F103的项目中,利用Keil开发环境进行调试,能够高效地实现一个功能丰富的嵌入式系统,为各类实际应用奠定坚实基础。希望以上内容能给大家在类似项目开发中带来一些启发。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐