STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片
STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片
STM32基础工程生成
首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到72M主频:
配置SPI前,首先查看WK2124的芯片手册,手册里面说明了WK2124的SPI最高支持到10M并且使用SPI模式0,SPI的模式0就是时钟空闲电平为低电平且在第一个时钟延采样:
所以STM32CUBEMX需要这样配置:
IO配置:
- WK2124的硬件复位引脚,这个引脚最好接上,使用STM32的IO进行控制
- WK2124的片选引脚
- 如果用WK2124的中断,那么还需要配置一个IO为外部中断
WK2124驱动代码
代码已经测试通过无问题,贴一下:
头文件
/** wk2xxx.h** Created on: Jun 17, 2021* Author: hello*/#ifndef SRC_WK2XXX_H_
#define SRC_WK2XXX_H_#include "main.h"#define WK2XXX_GENA 0X00
#define WK2XXX_GRST 0X01
#define WK2XXX_GMUT 0X02
#define WK2XXX_GIER 0X10
#define WK2XXX_GIFR 0X11
#define WK2XXX_GPDIR 0X21
#define WK2XXX_GPDAT 0X31
//wkxxxx slave uarts rigister address defines#define WK2XXX_SPAGE 0X03
//PAGE0
#define WK2XXX_SCR 0X04
#define WK2XXX_LCR 0X05
#define WK2XXX_FCR 0X06
#define WK2XXX_SIER 0X07
#define WK2XXX_SIFR 0X08
#define WK2XXX_TFCNT 0X09
#define WK2XXX_RFCNT 0X0A
#define WK2XXX_FSR 0X0B
#define WK2XXX_LSR 0X0C
#define WK2XXX_FDAT 0X0D
#define WK2XXX_FWCR 0X0E
#define WK2XXX_RS485 0X0F
//PAGE1
#define WK2XXX_BAUD1 0X04
#define WK2XXX_BAUD0 0X05
#define WK2XXX_PRES 0X06
#define WK2XXX_RFTL 0X07
#define WK2XXX_TFTL 0X08
#define WK2XXX_FWTH 0X09
#define WK2XXX_FWTL 0X0A
#define WK2XXX_XON1 0X0B
#define WK2XXX_XOFF1 0X0C
#define WK2XXX_SADR 0X0D
#define WK2XXX_SAEN 0X0E
#define WK2XXX_RTSDLY 0X0F//WK串口扩展芯片的寄存器的位定义
//wkxxx register bit defines
// GENA
#define WK2XXX_UT4EN 0x08
#define WK2XXX_UT3EN 0x04
#define WK2XXX_UT2EN 0x02
#define WK2XXX_UT1EN 0x01
//GRST
#define WK2XXX_UT4SLEEP 0x80
#define WK2XXX_UT3SLEEP 0x40
#define WK2XXX_UT2SLEEP 0x20
#define WK2XXX_UT1SLEEP 0x10
#define WK2XXX_UT4RST 0x08
#define WK2XXX_UT3RST 0x04
#define WK2XXX_UT2RST 0x02
#define WK2XXX_UT1RST 0x01
//GIER
#define WK2XXX_UT4IE 0x08
#define WK2XXX_UT3IE 0x04
#define WK2XXX_UT2IE 0x02
#define WK2XXX_UT1IE 0x01
//GIFR
#define WK2XXX_UT4INT 0x08
#define WK2XXX_UT3INT 0x04
#define WK2XXX_UT2INT 0x02
#define WK2XXX_UT1INT 0x01
//SPAGE
#define WK2XXX_SPAGE0 0x00
#define WK2XXX_SPAGE1 0x01
//SCR
#define WK2XXX_SLEEPEN 0x04
#define WK2XXX_TXEN 0x02
#define WK2XXX_RXEN 0x01
//LCR
#define WK2XXX_BREAK 0x20
#define WK2XXX_IREN 0x10
#define WK2XXX_PAEN 0x08
#define WK2XXX_PAM1 0x04
#define WK2XXX_PAM0 0x02
#define WK2XXX_STPL 0x01
//FCR
//SIER
#define WK2XXX_FERR_IEN 0x80
#define WK2XXX_CTS_IEN 0x40
#define WK2XXX_RTS_IEN 0x20
#define WK2XXX_XOFF_IEN 0x10
#define WK2XXX_TFEMPTY_IEN 0x08
#define WK2XXX_TFTRIG_IEN 0x04
#define WK2XXX_RXOUT_IEN 0x02
#define WK2XXX_RFTRIG_IEN 0x01
//SIFR
#define WK2XXX_FERR_INT 0x80
#define WK2XXX_CTS_INT 0x40
#define WK2XXX_RTS_INT 0x20
#define WK2XXX_XOFF_INT 0x10
#define WK2XXX_TFEMPTY_INT 0x08
#define WK2XXX_TFTRIG_INT 0x04
#define WK2XXX_RXOVT_INT 0x02
#define WK2XXX_RFTRIG_INT 0x01//TFCNT
//RFCNT
//FSR
#define WK2XXX_RFOE 0x80
#define WK2XXX_RFBI 0x40
#define WK2XXX_RFFE 0x20
#define WK2XXX_RFPE 0x10
#define WK2XXX_RDAT 0x08
#define WK2XXX_TDAT 0x04
#define WK2XXX_TFULL 0x02
#define WK2XXX_TBUSY 0x01
//LSR
#define WK2XXX_OE 0x08
#define WK2XXX_BI 0x04
#define WK2XXX_FE 0x02
#define WK2XXX_PE 0x01
//FWCRuint16_t WK_PortSendData(uint8_t port, const void* buf, uint16_t len);
uint16_t WK_PortRecvData(uint8_t port, void* buf, uint16_t len);
void WK_PortInit(uint8_t port, uint32_t fosc, uint32_t baudrate);
void WK_IRQHandler(void);
void WK_Rst(void);#endif /* SRC_WK2XXX_H_ */
源文件
/** wk2xxx.c** Created on: Jun 17, 2021* Author: hello*/#include "wk2xxx.h"
#include "spi.h"//
///
/// 移植修改区域
///
///// HAL库SPI句柄
#define WK_SPI_Handle (&hspi2)// 拉低RST引脚
#define WK_GPIO_RST_L() HAL_GPIO_WritePin(WK2124_RST1_GPIO_Port, WK2124_RST1_Pin, GPIO_PIN_RESET)// 拉高RST引脚
#define WK_GPIO_RST_H() HAL_GPIO_WritePin(WK2124_RST1_GPIO_Port, WK2124_RST1_Pin, GPIO_PIN_SET)// 片选引脚拉低
#define WK_GPIO_SEL_L() HAL_GPIO_WritePin(WK2124_CS1_GPIO_Port, WK2124_CS1_Pin, GPIO_PIN_RESET)// 片选引脚拉高
#define WK_GPIO_SEL_H() HAL_GPIO_WritePin(WK2124_CS1_GPIO_Port, WK2124_CS1_Pin, GPIO_PIN_SET)static void wk_delay_ms(uint32_t nms)
{HAL_Delay(nms);
}static uint8_t WK_SPI_ReadWriteByte(uint8_t TxData)
{uint8_t RxData = 0X00;if (HAL_SPI_TransmitReceive(WK_SPI_Handle, &TxData, &RxData, 1, 10) != HAL_OK){RxData = 0XFF;}return RxData;
}//
///
/// 驱动程序代码
///
///// 硬件复位(拉低复位引脚最低10毫秒进行复位)
void WK_Rst(void)
{WK_GPIO_RST_L();wk_delay_ms(50);WK_GPIO_RST_H();wk_delay_ms(50);
}void WK_WriteGReg(uint8_t reg, uint8_t value)
{WK_GPIO_SEL_L();WK_SPI_ReadWriteByte(reg);WK_SPI_ReadWriteByte(value);WK_GPIO_SEL_H();
}uint8_t WK_ReadGReg(uint8_t reg)
{uint8_t value = 0X00;WK_GPIO_SEL_L();WK_SPI_ReadWriteByte(0X40 | reg);value = WK_SPI_ReadWriteByte(0X00);WK_GPIO_SEL_H();return value;
}void WK_WriteSReg(uint8_t port, uint8_t reg, uint8_t value)
{WK_GPIO_SEL_L();WK_SPI_ReadWriteByte(((port - 1) << 4) | reg);WK_SPI_ReadWriteByte(value);WK_GPIO_SEL_H();
}uint8_t WK_ReadSReg(uint8_t port, uint8_t reg)
{uint8_t value = 0X00;WK_GPIO_SEL_L();WK_SPI_ReadWriteByte(0X40 | ((port - 1) << 4) | reg);value = WK_SPI_ReadWriteByte(0X00);WK_GPIO_SEL_H();return value;
}void WK_WriteFIFO(uint8_t port, const void* buf, uint16_t len)
{const uint8_t* p = (const uint8_t *)buf;WK_GPIO_SEL_L();WK_SPI_ReadWriteByte(0X80 | ((port - 1) << 4));while (len--){WK_SPI_ReadWriteByte(*p++);}WK_GPIO_SEL_H();
}void WK_ReadFIFO(uint8_t port, void* buf, uint16_t len)
{uint8_t* p = (uint8_t *)buf;WK_GPIO_SEL_L();WK_SPI_ReadWriteByte(0XC0 | ((port - 1) << 4));while (len--){*p++ = WK_SPI_ReadWriteByte(0X00);}WK_GPIO_SEL_H();
}void WK_PortCalcBaudrate(uint32_t fosc, uint32_t baudrate, uint8_t* BAUD0, uint8_t* BAUD1, uint8_t* PRES)
{float value = (float)fosc / (float)(baudrate << 4);*BAUD0 = (((uint32_t)value) - 1) & 0XFF;*BAUD1 = ((((uint32_t)value) - 1) >> 8) & 0XFF;*PRES = ((uint32_t)(value * 10)) % 10;
}uint16_t WK_PortSendData(uint8_t port, const void* buf, uint16_t len)
{uint8_t state = 0;uint16_t nsend = 0;state = WK_ReadSReg(port, WK2XXX_FSR);if (state & WK2XXX_TFULL) // 发送FIFO满{nsend = 0;} else{state = WK_ReadSReg(port, WK2XXX_TFCNT); // 读取发送FIFO已用空间nsend = 256 - state;nsend = nsend >= len ? len : nsend;WK_WriteFIFO(port, buf, nsend); // 将待发送的数据写入FIFO}return nsend; // 返回实际发送成功的数据量
}uint16_t WK_PortRecvData(uint8_t port, void* buf, uint16_t len)
{uint8_t state = 0;uint8_t nread = 0;state = WK_ReadSReg(port, WK2XXX_FSR);if (state & WK2XXX_RDAT) // 接收FIFO非空{nread = WK_ReadSReg(port, WK2XXX_RFCNT); // 查询FIFO中的数据量nread = len >= nread ? nread : len;WK_ReadFIFO(port, buf, nread); // 读取FIFO中的数据}return nread; // 返回实际读取到的数据量
}void WK_PortInit(uint8_t port, uint32_t fosc, uint32_t baudrate)
{uint8_t BAUD0 = 0, BAUD1 = 0, PRES = 0, value = 0, ret = 0;//// 使能子串口时钟//value = WK_ReadGReg(WK2XXX_GENA);value |= (1 << (port - 1));WK_WriteGReg(WK2XXX_GENA, value);ret = WK_ReadGReg(WK2XXX_GENA);//// 软件复位子串口//value = WK_ReadGReg(WK2XXX_GRST);value |= (1 << (port - 1));WK_WriteGReg(WK2XXX_GRST, value);ret = WK_ReadGReg(WK2XXX_GRST);//// 使能子串口总中断//value = WK_ReadGReg(WK2XXX_GIER);value |= (1 << (port - 1));WK_WriteGReg(WK2XXX_GIER, value);ret = WK_ReadGReg(WK2XXX_GIER);//// 使能子串口FIFO相关中断//value = WK_ReadSReg(port, WK2XXX_SIER);value |= WK2XXX_RFTRIG_IEN; // 接收FIFO触点中断
// value |= WK2XXX_TFTRIG_IEN; // 发送FIFO触点中断
// value |= WK2XXX_RXOUT_IEN; // 接收FIFO超时中断WK_WriteSReg(port, WK2XXX_SIER, value);ret = WK_ReadSReg(port, WK2XXX_SIER);//// 设置FCR寄存器//value = 0;value |= (1 << 0); // 复位接收FIFOvalue |= (1 << 1); // 复位发送FIFOvalue |= (1 << 2); // 使能接收FIFO(这一步必须)value |= (1 << 3); // 使能发送FIFO(这一步必须)value |= (0 << 4); // 设置接收FIFO触点固定为8字节value |= (0 << 6); // 设置发送FIFO触点固定为8字节WK_WriteSReg(port, WK2XXX_FCR, value);ret = WK_ReadSReg(port, WK2XXX_FCR);//// 切换到page1设置中断触点和波特率//WK_WriteSReg(port, WK2XXX_SPAGE, 1);ret = WK_ReadSReg(port, WK2XXX_SPAGE);WK_WriteSReg(port, WK2XXX_RFTL, 10); // 设置接收触点为10个字节ret = WK_ReadSReg(port, WK2XXX_RFTL);WK_WriteSReg(port, WK2XXX_TFTL, 10); // 设置发送触点为10个字节ret = WK_ReadSReg(port, WK2XXX_TFTL);WK_PortCalcBaudrate(fosc, baudrate, &BAUD0, &BAUD1, &PRES); // 计算波特率WK_WriteSReg(port, WK2XXX_BAUD1, BAUD1); // 设置BAUD1ret = WK_ReadSReg(port, WK2XXX_BAUD1);WK_WriteSReg(port, WK2XXX_BAUD0, BAUD0); // 设置BAUD0ret = WK_ReadSReg(port, WK2XXX_BAUD0);WK_WriteSReg(port, WK2XXX_PRES, PRES); // 设置PRESret = WK_ReadSReg(port, WK2XXX_PRES);//// 切换回page0//WK_WriteSReg(port, WK2XXX_SPAGE, 0);ret = WK_ReadSReg(port, WK2XXX_SPAGE);//// 使能子串口收发//value = WK_ReadSReg(port, WK2XXX_SCR);value |= WK2XXX_TXEN;value |= WK2XXX_RXEN;WK_WriteSReg(port, WK2XXX_SCR, value);ret = WK_ReadSReg(port, WK2XXX_SCR);
}// 如果irq引脚接入了单片机的外部中断引脚,将该函数放入外部中断处理函数内。
// 对于WK2124所开启的中断可以这么处理:
void WK_IRQHandler(void)
{int i = 0;uint8_t GIFR = 0, SIFR = 0;// 读取子串口全局中断寄存器GIFR = WK_ReadGReg(WK2XXX_GIFR);// 查询4个子串口是否发生中断for (i = 0; i < 4; i++){if ((GIFR >> i) & 0X01){SIFR = WK_ReadSReg((i + 1), WK2XXX_SIFR);// 有接收FIFO触点中断if (SIFR & WK2XXX_RFTRIG_INT){// 调用WK_PortRecvData接收数据}// 有接收FIFO超时中断if (SIFR & WK2XXX_RXOVT_INT){}// 有发送FIFO触点中断if (SIFR & WK2XXX_TFTRIG_INT){}// 有发送FIFO空中断if (SIFR & WK2XXX_TFEMPTY_INT){}// 有接收FIFO数据错误中断if (SIFR & WK2XXX_FERR_INT){}}}
}/*int main()
{int nrecv = 0;uint8_t buffer[256];// 硬件复位一下WK_Rst();// 初始化四个端口WK_PortInit(1, 11059200, 9600); // WK2124晶振我用的是11.0592MHz的,这个值根据实际进行修改WK_PortInit(2, 11059200, 9600);WK_PortInit(3, 11059200, 9600);WK_PortInit(4, 11059200, 9600);// 发送数据WK_PortSendData(1, "helloworld\r\n", 12);WK_PortSendData(2, "helloworld\r\n", 12);WK_PortSendData(3, "helloworld\r\n", 12);WK_PortSendData(4, "helloworld\r\n", 12);// 接收数据,轮训方式nrecv = WK_PortRecvData(1, buffer, sizeof(buffer));if(nrecv != 0){// 处理数据}}*/
STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片相关推荐
- STM32CubeMX | 基于STM32使用HAL库实现USB组合设备之多路CDC
STM32CubeMX | 基于STM32使用HAL库实现USB组合设备之多路CDC 本博客完整代码下载地址:https://download.csdn.net/download/qq15347150 ...
- 基于STM32的HAL库的倒立摆控制(一)PWM输出
一 TIM初始化 首先初始化PWM引脚,在这里使用的是TIM4的ch3,设置PD14为复用输出,并连接到TIM4 GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitS ...
- 【STM32】HAL库 STM32CubeMX教程十四---SPI
前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 在我们的HAL库中,对硬件SPI函数做了很好的集成,使得之前SPI几百行代码,在HAL库中,只需 ...
- 【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(一)
前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 本文 1首先讲解什么是FMC及SDRAM,W9825G6KH芯片原理,2基于CubeMx创建工程 ...
- 【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)
前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...
- 【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )
前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 在之前的标准库中,STM32的硬件IIC非常复杂,更重要的是它并不稳定,所以都不推荐使用. 但是 ...
- 【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(二)
前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 上一讲我们说了CubeMX配置SDRAM的一些基本配置,还有FMC跟SDRAM的讲解,这一讲我们 ...
- 【STM32】HAL库 STM32CubeMX教程十---DAC
前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...
- 【STM32】HAL库 STM32CubeMX教程七---PWM输出(呼吸灯)
前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...
最新文章
- MySQL02-升级
- spark 入门及集群环境搭建
- oracle11g导出表时会发现少表,空表导不出解决方案。
- Android Load Picture Asynchronously
- Hibernate 双向一对多映射
- Word vba之遍历段落、识别固定段头、设置样式
- 微信免费检测僵尸粉方法,微信免费检测僵尸粉工具
- 2017年下半年综合素质作文
- 快递企业设长租公寓解决住宿 降低快递员流动率
- CTF题库实验吧 py的交易
- uva 10019 Funny Encryption Method
- C++ 两两交换链表中的节点
- Hive中使用sort_array函数解决collet_list列表排序混乱问题
- Dijkstra算法指定任意两点距离(邻接矩阵法)
- Rocket Pool 、InfStones 、Lido 三种质押服务浅析
- C#异常处理try catch
- 卖书如何通过B站引流?方法用对后效果都不会太差
- xx.exe 中的 0x014180bd 处有未经处理的异常: 0xC0000005: 读取位置 0xfeeefeee 时发生访问冲突(当指针访问异常时,应考虑是不是对象未创建)。
- div盒子水平垂直居中的几种方式
- 利用vbs将word、excel、ppt转换成pdf