C语言常用的工具函数(模拟SPI)
#define CLK_DELAY 6 //us (1/2的SPI时钟周期 程序执行带来1us左右误差 1-2 2-3)
#define DATA_DELAY 200 //同一帧读写指令之间的间隔
#define CMD_DELAY 10000 //不同帧读写指令之间的间隔
#define SET_CLK_LOW GPIOA->BRR = (uint32_t)GPIO_PIN_8
#define SET_CLK_HIGH GPIOA->BSRR = (uint32_t)GPIO_PIN_8
#define SET_MOSI_LOW GPIOB->BRR = (uint32_t)GPIO_PIN_10
#define SET_MOSI_HIGH GPIOB->BSRR = (uint32_t)GPIO_PIN_10
#define SET_CS_LOW GPIOB->BRR = (uint32_t)GPIO_PIN_5
#define SET_CS_HIGH GPIOB->BSRR = (uint32_t)GPIO_PIN_5
#define READ_MISO HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
#define Dummy_Byte 0xFF //读取时MISO发送的数据,可以为任意数据
/**
* @brief SPI读写函数
* @note
* @param byte 发送的字节
*
* @retval 收到的字节
* @author yangFei
* @date 20210728
* @note 本函数内部需实现CPOL=0,CPHA=1, MSB first格式的模拟SPI
*/
static uint8_t spi_rw(uint8_t byte)
{
uint8_t i, rx_data=0;
for(i=0; i<8; i++) // 循环8次
{
SET_CLK_HIGH; //拉高时钟
if(byte&0x80)
{
SET_MOSI_HIGH; //若最高位为高,则输出高
}
else
{
SET_MOSI_LOW; //若最低位为低,则输出低
}
byte <<= 1; // 低一位移位到最高位
delay_us(CLK_DELAY);
SET_CLK_LOW; //拉低时钟
rx_data <<= 1; //数据左移
if(READ_MISO)
rx_data++; //若从从机接收到高电平,数据自加一
delay_us(CLK_DELAY);
}
return (rx_data); //返回数据
}
/**
* @brief SPI多读
* @note
* @param data 存储读取数据的存放缓存区
* @param len 读取的数据长度
*
* @retval
* @author yangFei
* @date 20210728
* @note 本函数内部需实现多字节读取功能
*/
void spi_read(uint8_t *data, uint8_t len)
{
for(uint8_t i=0; i<len; i++)
{
data[i] = spi_rw(Dummy_Byte);
}
}
/**
* @brief SPI多写.
* @note
* @param data 存储发送数据的存放缓存区
* @param len 发送的数据长度
*
* @retval 写入成功返回0;失败返回非0
* @author yangFei
* @date 20210728
* @note 本函数内部需实现多字节发送功能
*/
uint8_t spi_write(uint8_t *data, uint8_t len)
{
uint8_t rx_data[len];
memset(rx_data, 0, len);
for(uint8_t i=0; i<len; i++)
{
spi_rw(data[i]);
}
delay_us(CLK_DELAY);
spi_read(rx_data, len);
if(memcmp(data, rx_data, len))//tx != rx
return 1;
else return 0;
}