HAL库编写的IIC与SPI模块代码,包括start/stop,发送/接收字节,发送/接收应答等
使用时需要根据从机电气属性修改传输速率与延时
不要忘了根据需求修改IO口
Delay函数可用GPT生成
IIC代码如下:
#include "stm32f4xx_hal.h"
#include "Delay.h"
//SDA:PB12 SCL:PB13
/**
* 函 数:I2C写SDA与SCL引脚电平
* 参 数:写入的电平(0或1)
* 返 回 值:无
* 注意事项:为防止从机跟不上主机的翻转速度,写入后延时4微秒
* 此项根据从机IIC传输电气属性得知
*/
void IIC_W_SDA(uint8_t bitvalue)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, (GPIO_PinState)bitvalue);
delay_us(4);
}
void IIC_W_SCL(uint8_t bitvalue)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, (GPIO_PinState)bitvalue);
delay_us(4);
}
/**
* 函 数:I2C读SDA引脚电平
* 参 数:无
* 返 回 值:读出的电平(0或1)
* 注意事项:为防止从机跟不上主机的翻转速度,读出后延时4微秒
*/
uint8_t IIC_R_SDA(void)
{
uint8_t bitvalue;
bitvalue = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12);
delay_us(4);
return bitvalue;
}
/**
* 函 数:I2C初始化
* 参 数:无
* 返 回 值:无
* 注意事项:无
*/
void IIC_Init(void)
{
//时钟使能
__HAL_RCC_GPIOB_CLK_ENABLE();
//IO口模式
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_Init.Pin = GPIO_PIN_12 | GPIO_PIN_13;
GPIO_Init.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB, &GPIO_Init);
//默认初始化后引脚电平为高电平
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_13, GPIO_PIN_SET);
}
/**
* 函 数:I2C传输开始
* 参 数:无
* 返 回 值:无
* 注意事项:按照IIC起始逻辑编写
*/
void IIC_Start(void)
{
//手动拉高电平
IIC_W_SCL(1);
IIC_W_SDA(1);
//进入IIC传输
IIC_W_SDA(0);
IIC_W_SCL(0);
}
/**
* 函 数:I2C传输终止
* 参 数:无
* 返 回 值:无
* 注意事项:按照IIC终止逻辑编写
*/
void IIC_Stop(void)
{
//手动拉低电平
IIC_W_SDA(0);
//终止信号
IIC_W_SCL(1);
IIC_W_SDA(1);
}
/**
* 函 数:I2C发送一个字节
* 参 数:要发送的数据
* 返 回 值:无
* 注意事项:高位先行,先把数据放在SDA上,再拉高SCL读取
*/
void IIC_SendByte(uint8_t Byte)
{
uint8_t i;
for(i = 0;i < 8;i++)
{
IIC_W_SDA(Byte & (0X80 >> i));//提取出第i位的数据
IIC_W_SCL(1);
IIC_W_SCL(0);
}
}
/**
* 函 数:I2C接收一个字节
* 参 数:无
* 返 回 值:无
* 注意事项:高位先行,先把数据放在SDA上,再拉高SCL读取
*/
uint8_t IIC_ReceiveByte(void)
{
uint8_t i, Byte = 0X00;
IIC_W_SDA(1);
for(i = 0;i < 8;i++)
{
IIC_W_SCL(1);
if(IIC_R_SDA() == 1)
Byte |= (0X80 >> i);
IIC_W_SCL(0);
}
return Byte;
}
/**
* 函 数:I2C发送应答
* 参 数:无
* 返 回 值:无
* 注意事项:无
*/
void IIC_SendACK(uint8_t AckBit)
{
IIC_W_SDA(AckBit);//提取出第i位的数据
IIC_W_SCL(1);
IIC_W_SCL(0);
}
/**
* 函 数:I2C接收应答
* 参 数:无
* 返 回 值:无
* 注意事项:无
*/
uint8_t IIC_ReceiveAck(void)
{
uint8_t AckBit;
IIC_W_SDA(1);
IIC_W_SCL(1);
AckBit = IIC_R_SDA();
IIC_W_SCL(0);
return AckBit;
}
SPI代码如下:
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32f4xx_hal_rcc.h"
#include "NFR24L01_SPI.h"
//CSN PC3 MOSI PC5 SCK PC6 MISO PC4
#define CSN GPIO_PIN_3
#define MISO GPIO_PIN_4
#define MOSI GPIO_PIN_5
#define SCK GPIO_PIN_6
/**
* 函 数:SPI写CSN引脚电平
* 参 数:BitValue 协议层传入的当前需要写入CSN的电平,范围0~1
* 返 回 值:无
* 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置CSN为低电平,
* 当BitValue为1时,需要置CSN为高电平
*/
void SPI_W_CSN(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOC, CSN, (GPIO_PinState)BitValue);//根据BitValue,设置CSN引脚的电平
}
/**
* 函 数:SPI写SCK引脚电平
* 参 数:BitValue 协议层传入的当前需要写入SCK的电平,范围0~1
* 返 回 值:无
* 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCK为低电平,
* 当BitValue为1时,需要置SCK为高电平
*/
void SPI_W_SCK(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOC, SCK, (GPIO_PinState)BitValue);//根据BitValue,设置SCK引脚的电平
}
/**
* 函 数:SPI写MOSI引脚电平
* 参 数:BitValue 协议层传入的当前需要写入MOSI的电平,范围0~0xFF
* 返 回 值:无
* 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置MOSI为低电平,
* 当BitValue非0时,需要置MOSI为高电平
*/
void SPI_W_MOSI(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOC, MOSI, (GPIO_PinState)BitValue);//根据BitValue,设置MOSI引脚的电平,BitValue要实现非0即1的特性
}
/**
* 函 数:SPI读MISO引脚电平
* 参 数:无
* 返 回 值:协议层需要得到的当前MISO的电平,范围0~1
* 注意事项:此函数需要用户实现内容,当前MISO为低电平时,返回0,当前MISO为高电平时,返回1
*/
uint8_t SPI_R_MISO(void)
{
return HAL_GPIO_ReadPin(GPIOC, MISO); //读取MISO电平并返回
}
/**
* 函 数:SPI初始化
* 参 数:无
* 返 回 值:无
* 注意事项:此函数需要用户实现内容,实现CSN、SCK、MOSI和MISO引脚的初始化
*/
void SPI_Init(void)
{
__HAL_RCC_GPIOC_CLK_ENABLE(); //开启GPIOC的时钟
//GPIO初始化
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = CSN/*GPIO_PIN_3*/ | MOSI/*GPIO_PIN_5*/ | SCK/*GPIO_PIN_6*/;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;//配置为推挽输出模式
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;//配置高速输出
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.Pin = MISO/*GPIO_Pin_4*/;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;//配置为输入模式
GPIO_InitStructure.Pull = GPIO_PULLUP;//配置为上拉输入
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);//配置MISO(PC4)为上拉输入模式
//设置默认电平
SPI_W_CSN(1);//CSN默认高电平
SPI_W_SCK(0);//SCK默认低电平
}
//协议层
/**
* 函 数:SPI起始与终止
* 参 数:无
* 返 回 值:无
* 注意事项:无
*/
void SPI_Start(void)
{
SPI_W_CSN(1);
SPI_W_CSN(0);
}
void SPI_Stop(void)
{
SPI_W_CSN(0);
SPI_W_CSN(1);
}
/**
* 函 数:SPI交换(swap)传输一个字节,使用SPI模式0
* 参 数:ByteSend 要发送的一个字节
* 返 回 值:接收的一个字节
*/
uint8_t SPI_SwapByte(uint8_t ByteSend)
{
uint8_t i, ByteReceive = 0x00; //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
for (i = 0; i < 8; i ++) //循环8次,依次交换每一位数据
{
SPI_W_MOSI(ByteSend & (0x80 >> i)); //使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线
SPI_W_SCK(1); //拉高SCK,上升沿移出数据
if (SPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);} //读取MISO数据,并存储到Byte变量
//当MISO为1时,置变量指定位为1,当MISO为0时,不做处理,指定位为默认的初值0
SPI_W_SCK(0); //拉低SCK,下降沿移入数据
}
return ByteReceive; //返回接收到的一个字节数据
}
立个flag:本月之前把Veriog的语法写出来!!!
如有错误,欢迎指正