打印
[应用相关]

STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片

[复制链接]
1786|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
labasi|  楼主 | 2021-8-4 14:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
STM32基础工程生成
首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到72M主频:


配置SPI前,首先查看WK2124的芯片手册,手册里面说明了WK2124的SPI最高支持到10M并且使用SPI模式0,SPI的模式0就是时钟空闲电平为低电平且在第一个时钟延采样:

所以STM32CUBEMX需要这样配置:

IO配置:

WK2124的硬件复位引脚,这个引脚最好接上,使用STM32的IO进行控制
WK2124的片选引脚
如果用WK2124的中断,那么还需要配置一个IO为外部中断



使用特权

评论回复
沙发
labasi|  楼主 | 2021-8-4 14:25 | 只看该作者
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
//FWCR

uint16_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_ */


使用特权

评论回复
板凳
labasi|  楼主 | 2021-8-4 14:25 | 只看该作者
源文件
/*
* 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);  // 复位接收FIFO
        value |= (1 << 1);  // 复位发送FIFO
        value |= (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);  // 设置BAUD1
        ret = WK_ReadSReg(port, WK2XXX_BAUD1);

        WK_WriteSReg(port, WK2XXX_BAUD0, BAUD0);  // 设置BAUD0
        ret = WK_ReadSReg(port, WK2XXX_BAUD0);

        WK_WriteSReg(port, WK2XXX_PRES, PRES);    // 设置PRES
        ret = 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)
        {
                // 处理数据
        }
       
}

*/


使用特权

评论回复
地板
afei8856| | 2021-10-16 15:21 | 只看该作者
能否共享一下源文件,网页看着确实别扭

使用特权

评论回复
5
lidi911| | 2021-10-16 18:40 | 只看该作者
谢谢楼主分享代码

使用特权

评论回复
6
cmyldd| | 2022-5-30 18:16 | 只看该作者
楼主能否分享工程文件的?

使用特权

评论回复
7
hellosdc| | 2022-6-7 09:01 | 只看该作者
这个串口的效果怎么样?

使用特权

评论回复
8
geraldbetty| | 2022-6-7 11:01 | 只看该作者
感觉串口传输好复杂  

使用特权

评论回复
9
gygp| | 2022-6-7 16:30 | 只看该作者
能够做服务器的传输转发吗?

使用特权

评论回复
10
zerorobert| | 2022-6-21 21:22 | 只看该作者
SPI转四路串口的速度有损失吗?

使用特权

评论回复
11
wengh2016| | 2022-6-22 19:09 | 只看该作者
如何实现多路串口数据的传输呢?

使用特权

评论回复
12
soodesyt| | 2022-7-10 14:34 | 只看该作者
SPI驱动WK2124好用吗

使用特权

评论回复
13
aspoke| | 2022-7-10 15:45 | 只看该作者
如何区分是来自哪个串口的数据  

使用特权

评论回复
14
hilahope| | 2022-7-10 16:57 | 只看该作者
WK2124是什么芯片   

使用特权

评论回复
15
mattlincoln| | 2022-7-10 19:23 | 只看该作者
这个波特率是最大多少  

使用特权

评论回复
16
timfordlare| | 2022-7-10 20:03 | 只看该作者
stm32f103vct6有足够的串口了。  

使用特权

评论回复
17
geraldbetty| | 2022-7-10 21:04 | 只看该作者
stm32就有很多的 串口了。

使用特权

评论回复
18
Uriah| | 2022-10-3 12:30 | 只看该作者

微探针技术都属于侵入型攻击

使用特权

评论回复
19
Bblythe| | 2022-10-3 15:29 | 只看该作者

极限情况下可以定义的变量可占 247 个字节

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

3314

帖子

2

粉丝