IIC和SPI模块代码(HAL库,直接取用)

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的语法写出来!!!

如有错误,欢迎指正

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值