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转四路串口芯片相关推荐

  1. STM32CubeMX | 基于STM32使用HAL库实现USB组合设备之多路CDC

    STM32CubeMX | 基于STM32使用HAL库实现USB组合设备之多路CDC 本博客完整代码下载地址:https://download.csdn.net/download/qq15347150 ...

  2. 基于STM32的HAL库的倒立摆控制(一)PWM输出

    一 TIM初始化 首先初始化PWM引脚,在这里使用的是TIM4的ch3,设置PD14为复用输出,并连接到TIM4 GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitS ...

  3. 【STM32】HAL库 STM32CubeMX教程十四---SPI

    前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 在我们的HAL库中,对硬件SPI函数做了很好的集成,使得之前SPI几百行代码,在HAL库中,只需 ...

  4. 【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(一)

    前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 本文 1首先讲解什么是FMC及SDRAM,W9825G6KH芯片原理,2基于CubeMx创建工程 ...

  5. 【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)

    前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...

  6. 【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )

    前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 在之前的标准库中,STM32的硬件IIC非常复杂,更重要的是它并不稳定,所以都不推荐使用. 但是 ...

  7. 【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(二)

    前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 上一讲我们说了CubeMX配置SDRAM的一些基本配置,还有FMC跟SDRAM的讲解,这一讲我们 ...

  8. 【STM32】HAL库 STM32CubeMX教程十---DAC

    前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...

  9. 【STM32】HAL库 STM32CubeMX教程七---PWM输出(呼吸灯)

    前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...

最新文章

  1. MySQL02-升级
  2. spark 入门及集群环境搭建
  3. oracle11g导出表时会发现少表,空表导不出解决方案。
  4. Android Load Picture Asynchronously
  5. Hibernate 双向一对多映射
  6. Word vba之遍历段落、识别固定段头、设置样式
  7. 微信免费检测僵尸粉方法,微信免费检测僵尸粉工具
  8. 2017年下半年综合素质作文
  9. 快递企业设长租公寓解决住宿 降低快递员流动率
  10. CTF题库实验吧 py的交易
  11. uva 10019 Funny Encryption Method
  12. C++ 两两交换链表中的节点
  13. Hive中使用sort_array函数解决collet_list列表排序混乱问题
  14. Dijkstra算法指定任意两点距离(邻接矩阵法)
  15. Rocket Pool 、InfStones 、Lido 三种质押服务浅析
  16. C#异常处理try catch
  17. 卖书如何通过B站引流?方法用对后效果都不会太差
  18. xx.exe 中的 0x014180bd 处有未经处理的异常: 0xC0000005: 读取位置 0xfeeefeee 时发生访问冲突(当指针访问异常时,应考虑是不是对象未创建)。
  19. div盒子水平垂直居中的几种方式
  20. 利用vbs将word、excel、ppt转换成pdf

热门文章

  1. SAP学习第一篇——SAP模块介绍
  2. 团体程序设计天梯赛练习题-持续更新中
  3. 计算机网络centos下实验1.1(Linux常用命令+Linux网络基础)
  4. 一线互联网架构师筑基必备技能之Java篇,一招彻底弄懂!
  5. CTFShow-大赛原题改编(未完慢慢更)
  6. 扫盲篇之蓝牙Mesh是什么
  7. 见缝插针php源码,见缝插针 小游戏源码
  8. 扫码授权平台_如何授权公众号设置关注后投票?
  9. 有序数组合并及等长数组对位穿插
  10. 有限状态机详解(转载)