0
点赞
收藏
分享

微信扫一扫

STM32F407用wk2124芯片编写SPI转四路串口驱动


目录

​​引言​​

​​一. SPI通信配置​​

​​1.GPIO初始化设置​​

​​2.SPI参数配置​​

​​3.读写函数​​

​​4.速度设置​​

​​二、WK2124逻辑代码编写​​

​​1.片选初始化​​

​​2. 写寄存器函数​​

​​3. 读寄存器函数​​

​​4. 写FIFO函数​​

​​5.读FIFO函数​​

​​6. WK2124初始化函数​​

​​7.wk2124关闭及复位函数​​

​​8. 波特率设置函数​​

​​8.发送字节函数​​

​​9. 接收数据函数​​

​​三、测试​​

引言

因为项目用到了wk2124芯片来进行串口扩展,网上找了好多资料没有现成的,根据商家提供的demo,它是基于103写的,所以根据自己板子的实际情况进行了改写,并且学习一下里面的主要函数及我对函数的理解

原理图

STM32F407用wk2124芯片编写SPI转四路串口驱动_串口通信

 用到5个引脚,片选CS、时钟SCK、MOSI、MISO和中断IRQ,因为RST设置的是板子连电后电容充电,所以会自动复位,不用这个引脚。

一. SPI通信配置

1.GPIO初始化设置

GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能SPI2时钟,在APB1时钟里面
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
//PB13-15分别复用为SCK,MISO,MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

2.SPI参数配置

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_02

 

 

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_03

 

因为发送接收是同时进行,所以选择全双工,SPI设置为主模式 ,大小为8bit,时钟默认拉低,第二个时钟沿开始捕捉,数据格式SPI_FirstBit(选择是MSB还是LSB),选择MSB方式,举个例子假设用16bit,就是[15,0]这样,如果是LSB就是[0,15]这样。

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟悬空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第二个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件(使用SSI位)管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

SPI_Cmd(SPI2, ENABLE); //使能SPI外设
SPI2_ReadWriteByte(0xff);//启动传输

3.读写函数

u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //发送缓存空标志位
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
retry=0;

while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)//接受缓存非空标志位
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}

读写函数中,用SPI_I2S_GetFlagStatus不断去获取TXE和RXNE的状态,如果是非空就继续,如果为空就调用Send和Rece函数去发送接收数据,当retry标志连续超过200次,就返回0,发送/接收失败。

4.速度设置

void SPI2_SetSpeed(u8 SpeedSet)
{
SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet ;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2,ENABLE);
}

 

二、WK2124逻辑代码编写

引脚对应关系

CS    PB12
SCK   PB13
MOSI  PB15
MISO  PB14
IRQ   PB1

 

1.片选初始化

void SPI_CS_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PB12端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //IO口速度为100MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB12
GPIO_SetBits(GPIOB,GPIO_Pin_12); //PB12 输出高
}

 

2. 写寄存器函数

void WK2124WriteReg(unsigned char port,unsigned char reg,unsigned char dat)
{
SPI_CS_L();//片选使能
SPI2_ReadWriteByte(((port-1)<<4)+reg); //写控制字节
SPI2_ReadWriteByte(dat); //写数据
SPI_CS_H();//片选无效
}

首先把片选信号拉低,然后写入控制命令,再写入数据,写完之后再拉高片选,对于其中的控制字节((port-1)<<4)+reg可以根据数据手册得知,port:为子串口的端口号(C0\C1),reg是目标寄存器,dat是数据。

STM32F407用wk2124芯片编写SPI转四路串口驱动_wk2124驱动_04

6,7位为默认为0,0,C1,C0为串口通道,可选值为00,01,10,11分别表示4个串口,默认设置为00,通过传入参数port(port设置的是1,2,3,4,但是因为从0开始,所以要port-1)来进行改变,然后左移4位变成00 0000,然后加上初始的默认值0000 0000,最后加上要写入的寄存器,所以其实是0x00+(port-1)<<4)+reg,然后将这个cmd传入spi读写函数进行读写。

 

3. 读寄存器函数

unsigned char WK2124ReadReg(unsigned char port,unsigned char reg)
{
unsigned char rec_data;
SPI_CS_L(); //片选使能
SPI2_ReadWriteByte(0x40+((port-1)<<4)+reg);//写控制字节
rec_data=SPI2_ReadWriteByte(0);//接收返回的数据
SPI_CS_H(); //片选无效
return rec_data;
}

4. 写FIFO函数

void WK2124WriteFifo(unsigned char port,unsigned char *wbuf,unsigned int len)
{ unsigned char n;
SPI_CS_L(); // 片选有效
SPI2_ReadWriteByte(0x80+((port-1)<<4)); //写FIFO控制指令
for(n=0;n<len;n++)
{
SPI2_ReadWriteByte(*(wbuf+n));
}
SPI_CS_H(); //片选无效

}

  port:为子串口的端口号(C0\C1), *wbuf:写入数据部分, len:  写入数据长度。

大部分和读写寄存器相同,主要控制字节不同,其次可以一次写入多个数据。

STM32F407用wk2124芯片编写SPI转四路串口驱动_stm32_05

控制字节的变化主要是初始SPI的CMD为1000 0000,也就是0x80,其他一样。

 

5.读FIFO函数

void WK2124WriteFifo(unsigned char port,unsigned char *wbuf,unsigned int len)
{ unsigned char n;
SPI_CS_L(); // 片选有效
SPI2_ReadWriteByte(0x80+((port-1)<<4)); //写FIFO控制指令
for(n=0;n<len;n++)
{
SPI2_ReadWriteByte(*(wbuf+n));
}
SPI_CS_H(); //片选无效

}

 

6. WK2124初始化函数

首先使能子串口时钟

unsigned char gena,grst,gier,sier,scr;
//使能子串口时钟
gena=WK2124ReadReg(WK2124_GPORT,WK2124_GENA);
switch (port)
{
case 1://使能子串口1的时钟
gena|=WK2124_UT1EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
case 2://使能子串口2的时钟
gena|=WK2124_UT2EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
case 3://使能子串口3的时钟
gena|=WK2124_UT3EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
case 4://使能子串口4的时钟
gena|=WK2124_UT4EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
}

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_06

在头文件中对GENA全局寄存器进行了宏定义:

#define   WK2124_UT4EN  0x08
#define WK2124_UT3EN 0x04
#define WK2124_UT2EN 0x02
#define WK2124_UT1EN 0x01

根据数据手册说明,低位的0,1,2,3位置1,就使能哪个子串口,如ut2使能就是0000 0010,也就是0x02。

接下来进行串口复位

//软件复位子串口
grst=WK2124ReadReg(WK2124_GPORT,WK2124_GRST);
switch (port)
{
case 1://软件复位子串口1
grst|=WK2124_UT1RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
case 2://软件复位子串口2
grst|=WK2124_UT2RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
case 3://软件复位子串口3
grst|=WK2124_UT3RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
case 4://软件复位子串口4
grst|=WK2124_UT4RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
}

STM32F407用wk2124芯片编写SPI转四路串口驱动_wk2124驱动_07

与上面一样,第四位哪个置1,表示哪个子串口进行复位。 

接下来使能串口中断

//使能子串口中断,包括子串口总中断和子串口内部的接收中断,和设置中断触点
gier=WK2124ReadReg(WK2124_GPORT,WK2124_GIER);
switch (port)
{
case 1://子串口1中断使能
gier|=WK2124_UT1IE;
WK2124WriteReg(WK2124_GPORT,WK2124_GIER,gier);
break;
case 2://子串口2中断使能
gier|=WK2124_UT2IE;
WK2124WriteReg(WK2124_GPORT,WK2124_GIER,gier);
break;
case 3://子串口3中断使能
gier|=WK2124_UT3IE;
WK2124WriteReg(WK2124_GPORT,WK2124_GIER,gier);
break;
case 4://子串口4中断使能
gier|=WK2124_UT4IE;
WK2124WriteReg(WK2124_GPORT,WK2124_GIER,gier);
break;
}

STM32F407用wk2124芯片编写SPI转四路串口驱动_stm32_08

寄存器设置与上面一样。

//使能子串口接收触点中断和超时中断
sier=WK2124ReadReg(port,WK2124_SIER);
sier |= WK2124_RFTRIG_IEN;
WK2124WriteReg(port,WK2124_SIER,sier);
// 初始化FIFO和设置固定中断触点
WK2124WriteReg(port,WK2124_FCR,0XFF);
//设置任意中断触点,如果下面的设置有效,那么上面FCR寄存器中断的固定中断触点将失效
WK2124WriteReg(port,WK2124_SPAGE,1);//切换到page1
WK2124WriteReg(port,WK2124_RFTL,0X08);//设置接收触点8个字节
WK2124WriteReg(port,WK2124_TFTL,0X10);//设置发送触点为16个字节
WK2124WriteReg(port,WK2124_SPAGE,0);//切换到page0
//使能子串口的发送和接收使能
scr=WK2124ReadReg(port,WK2124_SCR);
scr|=WK2124_TXEN|WK2124_RXEN;
WK2124WriteReg(port,WK2124_SCR,scr);

 

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_09

STM32F407用wk2124芯片编写SPI转四路串口驱动_stm32f407_10

剩下的这些触点,页面设置,使能都一样,根据数据手册进行设置即可。

 

7.wk2124关闭及复位函数

void WK2124Close(unsigned char port)
{
unsigned char gena,grst;
//复位子串口
grst=WK2124ReadReg(WK2124_GPORT,WK2124_GRST);
switch (port)
{
case 1://软件复位子串口1
grst|=WK2124_UT1RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
case 2://软件复位子串口2
grst|=WK2124_UT2RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
case 3://软件复位子串口3
grst|=WK2124_UT3RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
case 4://软件复位子串口4
grst|=WK2124_UT4RST;
WK2124WriteReg(WK2124_GPORT,WK2124_GRST,grst);
break;
}
//关闭子串口时钟
gena=WK2124ReadReg(WK2124_GPORT,WK2124_GENA);
switch (port)
{
case 1://使能子串口1的时钟
gena&=~WK2124_UT1EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
case 2://使能子串口2的时钟
gena&=~WK2124_UT2EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
case 3://使能子串口3的时钟
gena&=~WK2124_UT3EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
case 4://使能子串口4的时钟
gena&=~WK2124_UT4EN;
WK2124WriteReg(WK2124_GPORT,WK2124_GENA,gena);
break;
}
}

先对GRST寄存器进行操作使其复位,然后利用~运算符关闭串口时钟,同时可以减少参数量。

 

8. 波特率设置函数

void WK2124SetBaud(unsigned char port,int baud)
{
unsigned char baud1,baud0,pres,scr;
//如下波特率相应的寄存器值,是在外部时钟为11.0592的情况下计算所得,如果使用其他晶振,需要重新计算
switch (baud)
{
case 600:
baud1=0x4;
baud0=0x7f;
pres=0;
break;
case 1200:
baud1=0x2;
baud0=0x3F;
pres=0;
break;
case 2400:
baud1=0x1;
baud0=0x1f;
pres=0;
break;
case 4800:
baud1=0x00;
baud0=0x8f;
pres=0;
break;
case 9600:
baud1=0x00;
baud0=0x47;
pres=0;
break;
case 19200:
baud1=0x00;
baud0=0x23;
pres=0;
break;
case 38400:
baud1=0x00;
baud0=0x11;
pres=0;
break;

case 76800:
baud1=0x00;
baud0=0x08;
pres=0;
break;

case 1800:
baud1=0x01;
baud0=0x7f;
pres=0;
break;
case 3600:
baud1=0x00;
baud0=0xbf;
pres=0;
break;
case 7200:
baud1=0x00;
baud0=0x5f;
pres=0;
break;
case 14400:
baud1=0x00;
baud0=0x2f;
pres=0;
break;
case 28800:
baud1=0x00;
baud0=0x17;
pres=0;
break;
case 57600:
baud1=0x00;
baud0=0x0b;
pres=0;
break;
case 115200:
baud1=0x00;
baud0=0x05;
pres=0;
break;
case 230400:
baud1=0x00;
baud0=0x02;
pres=0;
break;
default:
baud1=0x00;
baud0=0x00;
pres=0;
}

//关掉子串口收发使能
scr=WK2124ReadReg(port,WK2124_SCR);
WK2124WriteReg(port,WK2124_SCR,0);
//设置波特率相关寄存器
WK2124WriteReg(port,WK2124_SPAGE,1);//切换到page1
WK2124WriteReg(port,WK2124_BAUD1,baud1);
WK2124WriteReg(port,WK2124_BAUD0,baud0);
WK2124WriteReg(port,WK2124_PRES,pres);
WK2124WriteReg(port,WK2124_SPAGE,0);//切换到page0
//使能子串口收发使能
WK2124WriteReg(port,WK2124_SCR,scr);


}

计算公式:

STM32F407用wk2124芯片编写SPI转四路串口驱动_stm32f407_11

Reg整数部分减一并换算成16进制写入{BAUD1,BAUA0};如果还有小数部分,则小数部分*16,然后4舍5入后取整写入PRES。如果没有小数部分,只需把整数部分写入 { BAUD1,BAUA0},PRES写入0即可。

例子:

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_12

根据具体晶振去设置即可。

 

8.发送字节函数

unsigned int WK2124SendBuf(unsigned char port,unsigned char *sendbuf,unsigned int len)
{
unsigned int ret,tfcnt,sendlen;
unsigned char fsr;

fsr=WK2124ReadReg(port,WK2124_FSR);
if(~fsr&WK2124_TFULL )//子串口发送FIFO未满
{

tfcnt=WK2124ReadReg(port,WK2124_TFCNT);//读子串口发送fifo中数据个数
sendlen=256-tfcnt;//FIFO能写入的最多字节数

if(sendlen<len)
{
ret=sendlen;
WK2124WriteFifo(port,sendbuf,sendlen);
}
else
{
WK2124WriteFifo(port,sendbuf,len);
ret=len;
}
}

return ret;
}

 

9. 接收数据函数

unsigned int WK2124GetBuf(unsigned char port,unsigned char *getbuf)
{
unsigned int ret=0,rfcnt;
unsigned char fsr;
fsr=WK2124ReadReg(port,WK2124_FSR);
if(fsr&WK2124_RDAT )//子串口发送FIFO未满
{
rfcnt=WK2124ReadReg(port,WK2124_RFCNT);//读子串口发送fifo中数据个数
if(rfcnt==0)//当RFCNT寄存器为0的时候,有两种情况,可能是256或者是0,这个时候通过FSR来判断,如果FSR显示接收FIFO不为空,就为256个字节
{rfcnt=256;}
WK2124ReadFifo(port,getbuf,rfcnt);
ret=rfcnt;
}
return ret;
}

      最后有一点,UART端口输出为TTL电平,如果需要232或485电平的,需要加相应的电平转换芯片。

      踩坑记录:如果读写寄存器是0的情况下,将芯片的子串口短接,进行自收发测试,如果成功就说明子串口到外接的通信有问题,如果失败就说明2124和主控芯片之间的通信有问题,检查一下通信过程。

我有一步是SPI配置的时候预分频给了256,太大了导致通信失败,将它改为8分频。

要看一下SPI的CPOL,CPHA,应该在LOW状态捕捉第一个边沿,参考数据手册,否则的话也是收发有问题。

不同频率的晶振记得根据公式改写波特率,否则通信有问题。

还有好多坑,想不起来了。

三、测试

配置好后4个串口测试:

单个字符/数

STM32F407用wk2124芯片编写SPI转四路串口驱动_wk2124驱动_13

STM32F407用wk2124芯片编写SPI转四路串口驱动_wk2124驱动_14

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_15

STM32F407用wk2124芯片编写SPI转四路串口驱动_wk2124驱动_16

 

字符写入测试:

进行两次写入观察,写入的一致。

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_17

STM32F407用wk2124芯片编写SPI转四路串口驱动_spi转4路串口_18

 

FIFO串口4与STM32串口1通信测试:

STM32F407用wk2124芯片编写SPI转四路串口驱动_wk2124驱动_19

STM32F407用wk2124芯片编写SPI转四路串口驱动_串口通信_20

 

数据缓存区测试 :

STM32F407用wk2124芯片编写SPI转四路串口驱动_stm32f407_21

 

 

举报

相关推荐

0 条评论