ZW101模块驱动终于跑通了,卡了我好几天了,一开始我用的是串口中断去接收的数据,每次只接收一个字节,这样子存在很大的问题就是,接收10个以内的数据,可以接受到,但是接收10个以上的数据就会丢数据了
方式1串口中断
在usart.c的中,注意了在调试的过程中你想要用串口1去打印消息千万不要用重定向好的printf去打印,这样打印出来的数据会出错,在Send_Cmd()中用HAL_UART_Transmit去发送就没问题。
#include "sys.h"
#include "usart2.h"
//PA2 TX PA3 RX
/* 睡眠指令 */
uint8_t PS_SleepBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x33,0x00,0x37};
/* 清空指纹指令 */
uint8_t PS_EmptyBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0D,0x00,0x11};
/* 取消指令 */
uint8_t PS_CancelBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x30,0x00,0x34};
/* 蓝色LED灯开启指令 */
uint8_t PS_BlueLEDBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x03,0x01,0x01,0x00,0x00,0x49};
/* 红色LED灯双闪指令 */
uint8_t PS_RedLEDBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x04,0x04,0x02,0x00,0x50};
/* 绿色LED灯双闪指令 */
uint8_t PS_GreenLEDBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x02,0x02,0x02,0x00,0x4C};
/* 自动注册指纹指令 */
uint8_t PS_AutoEnrollBuffer[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x31,'\0','\0',0x04,0x00,0x0F,'\0','\0'};
/* 获取图像指令1 */
uint8_t PS_GetImageBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};
/* 生成特征1指令2 */
uint8_t PS_GetChar1Buffer[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x01,0x00,0x08};
/* 生成特征2指令 */
uint8_t PS_GetChar2Buffer[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x02,0x00,0x09};
/* 搜索模板指令 3*/
uint8_t PS_SearchMBBuffer[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x04,0x01,0x00,0x00,0xFF,0xFF,0x02,0x0C};
/* 删除模板指令 */
uint8_t PS_DeleteBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0C,'\0','\0',0x00,0x01,'\0','\0'};
/* 获取指纹唯一SN码指令 */
uint8_t PS_GetChipSN[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x34,0x00,0x00,0x39};
/* 握手指令 */
uint8_t PS_HandShake[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x35,0x00,0x39};
/* 读取有效模板数量指令 */
uint8_t PS_ValidTemplateNum[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x1D,0x00,0x21};
/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart2_rx_buf[USART2_REC_LEN];
/* 接收状态
* bit15, 接收完成标志
* bit14, 接收到0x0d
* bit13~0, 接收到的有效字节数目
*/
uint16_t g_usart2_rx_sta = 0;
uint8_t RxBuff[1]; //进入中断接收数据的数组
uint8_t DataBuff[5000]; //保存接收到的数据的数组
int RxLine=0; //接收到的数据长度
uint8_t g_rx2_buffer[RX2BUFFERSIZE]={0}; /* HAL库使用的串口接收缓冲 */
uint8_t RX=0;
UART_HandleTypeDef g_uart2_handle; /* UART句柄 */
uint8_t RX_Buff[20]={0};
extern UART_HandleTypeDef UART1_Handler; //UART句柄
/**
* @brief 串口X初始化函数
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
* 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
* @retval 无
*/
void usart2_Init(uint32_t baudrate)
{
GPIO_InitTypeDef gpio_init_struct;
USART_UX_CLK_ENABLE(); /* USART1 时钟使能 */
USART_TX_GPIO_CLK_ENABLE(); /* 发送引脚时钟使能 */
USART_RX_GPIO_CLK_ENABLE(); /* 接收引脚时钟使能 */
gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* TX引脚 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = USART_TX_GPIO_AF; /* 复用为USART1 */
HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); /* 初始化发送引脚 */
gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* RX引脚 */
gpio_init_struct.Alternate = USART_RX_GPIO_AF; /* 复用为USART1 */
HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 初始化接收引脚 */
g_uart2_handle.Instance = USART_UX; /* USART1 */
g_uart2_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart2_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
g_uart2_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */
g_uart2_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
g_uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
g_uart2_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART1中断通道 */
HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
HAL_UART_Init(&g_uart2_handle); /* HAL_UART_Init()会使能UART1 */
HAL_UART_Receive_IT(&g_uart2_handle,&RX, 1);
}
/**
* @brief 串口1中断服务函数
* @param 无
* @retval 无
*/
void USART_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_uart2_handle); /* 调用HAL库中断处理公用函数 */
}
//发送命令
uint8_t Send_Cmd(uint8_t* cmd,uint8_t len)
{
uint8_t i=0;
for(i=0;i<len;i++)
{
HAL_UART_Transmit(&UART1_Handler,cmd,1,10);
HAL_UART_Transmit(&g_uart2_handle,cmd,1,10);
cmd++;
}
return 1;
}
//自动注册指纹需要传入两字节ID号和一字节录入的次数
uint8_t PS_AutoEnroll(uint16_t ID,uint8_t number)
{
uint8_t i=6;
uint16_t sum;
PS_AutoEnrollBuffer[10]=ID>>8;
PS_AutoEnrollBuffer[11]=ID;//两个字节录入ID
PS_AutoEnrollBuffer[12]=number;//一字节录入的次数
PS_AutoEnrollBuffer[13]=0xff;
PS_AutoEnrollBuffer[14]=0x33;//两字节参数
for(;i<=14;i++)
{
sum=sum+PS_AutoEnrollBuffer[i];
}
PS_AutoEnrollBuffer[15]=sum>>8;
PS_AutoEnrollBuffer[16]=sum;
Send_Cmd(PS_AutoEnrollBuffer,17);
}
然后需要在主函数中将注册的代码发送
https://www.st.com/en/embedded-software/stm32cubef4.html#get-software
之后就要在串口中断回调函数中接收数据了,在这里也要用HAL_UART_Tranmit去发送不要用printf去打印消息。
方式1不太推荐因为接收的数据都是10个字节以上,会丢数据
方式二就不会丢数据了用的是串口+DMA中断
在usart.c中,注意如果你的hal库中找不到HAL_UARTEx_RxEventCallback这个函数,那么就需要去更新一下hal库了,这个些代码是基于STM32F407的。
#include "./SYSTEM/sys/sys.h"
#include "usart2.h"
//PA2 TX PA3 RX
/******************************************************************************************/
/********************** *************************END*******************************************/
/* 睡眠指令 */
uint8_t PS_SleepBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x33,0x00,0x37};
/* 清空指纹指令 */
uint8_t PS_EmptyBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0D,0x00,0x11};
/* 取消指令 */
uint8_t PS_CancelBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x30,0x00,0x34};
/* 蓝色LED灯开启指令 */
uint8_t PS_BlueLEDBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x03,0x01,0x01,0x00,0x00,0x49};
/* 红色LED灯双闪指令 */
uint8_t PS_RedLEDBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x04,0x04,0x02,0x00,0x50};
/* 绿色LED灯双闪指令 */
uint8_t PS_GreenLEDBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x02,0x02,0x02,0x00,0x4C};
/* 自动注册指纹指令 */
uint8_t PS_AutoEnrollBuffer[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x31,'\0','\0','\0',0xFF,0x33,'\0','\0'};
/* 获取图像指令1 */
uint8_t PS_GetImageBuffer[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};
/* 生成特征1指令2 */
uint8_t PS_GetChar1Buffer[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x01,0x00,0x08};
/* 生成特征2指令 */
uint8_t PS_GetChar2Buffer[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x02,0x00,0x09};
/* 搜索模板指令 3*/
uint8_t PS_SearchMBBuffer[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x04,0x01,0x00,0x00,0xFF,0xFF,0x02,0x0C};
/* 删除模板指令 */
uint8_t PS_DeleteBuffer[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0C,'\0','\0',0x00,0x01,'\0','\0'};
/* 获取指纹唯一SN码指令 */
uint8_t PS_GetChipSN[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x34,0x00,0x00,0x39};
/* 握手指令 */
uint8_t PS_HandShake[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x35,0x00,0x39};
/* 读取有效模板数量指令 */
uint8_t PS_ValidTemplateNum[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x1D,0x00,0x21};
/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart2_rx_buf[USART2_REC_LEN];
/* 接收状态
* bit15, 接收完成标志
* bit14, 接收到0x0d
* bit13~0, 接收到的有效字节数目
*/
uint16_t g_usart2_rx_sta = 0;
uint8_t RxBuff[1]; //进入中断接收数据的数组
uint8_t DataBuff[5000]; //保存接收到的数据的数组
int RxLine=0; //接收到的数据长度
uint8_t g_rx2_buffer[RX2BUFFERSIZE]={0}; /* HAL库使用的串口接收缓冲 */
uint8_t RX=0;
UART_HandleTypeDef g_uart2_handle; /* UART句柄 */
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;
extern UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
uint8_t receiveBata[20];
uint8_t BuffSize;
uint8_t flag=0;
/**
* @brief 串口X初始化函数
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
* 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
* @retval 无
*/
void usart2_Init(uint32_t baudrate)
{
GPIO_InitTypeDef gpio_init_struct;
USART_UX_CLK_ENABLE(); /* USART1 时钟使能 */
USART_TX_GPIO_CLK_ENABLE(); /* 发送引脚时钟使能 */
USART_RX_GPIO_CLK_ENABLE(); /* 接收引脚时钟使能 */
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* DMA1_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* TX引脚 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = USART_TX_GPIO_AF; /* 复用为USART1 */
HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); /* 初始化发送引脚 */
gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* RX引脚 */
gpio_init_struct.Alternate = USART_RX_GPIO_AF; /* 复用为USART1 */
HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 初始化接收引脚 */
g_uart2_handle.Instance = USART_UX; /* USART1 */
g_uart2_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart2_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
g_uart2_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */
g_uart2_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
g_uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
g_uart2_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
/* USART2 DMA Init */
/* USART2_RX Init */
hdma_usart2_rx.Instance = DMA1_Stream5;//数据流
hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;//通道
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;//传输方向外设到内存
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;//失能外设自增
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;//使能外设自增
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;//传输数据宽度
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_rx.Init.Mode = DMA_NORMAL;
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
{
printf("hdma_usart2_rx:ERROR\r\n");
}
__HAL_LINKDMA(&g_uart2_handle,hdmarx,hdma_usart2_rx);//DMA与串口连接
/* USART2_TX Init */
hdma_usart2_tx.Instance = DMA1_Stream6;
hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
{
printf("hdma_usart2_tx:ERROR\r\n");
}
__HAL_LINKDMA(&g_uart2_handle,hdmatx,hdma_usart2_tx);
HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART1中断通道 */
HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
HAL_UART_Init(&g_uart2_handle); /* HAL_UART_Init()会使能UART1 */
/* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
//HAL_UART_Receive_IT(&g_uart2_handle,&RX, 1);
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
flag=1;
BuffSize=Size;
HAL_UARTEx_ReceiveToIdle_DMA(&g_uart2_handle,receiveBata,sizeof(receiveBata));
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
}
/**
* @brief 串口1中断服务函数
* @param 无
* @retval 无
*/
void USART_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_uart2_handle); /* 调用HAL库中断处理公用函数 */
}
//发送命令
uint8_t Send_Cmd(uint8_t* cmd,uint8_t len)
{
uint8_t i=0;
for(i=0;i<len;i++)
{
//USART2_SendByte(*cmd);
HAL_UART_Transmit(&g_uart2_handle,cmd,1,10);
//printf("%x",*cmd);
HAL_UART_Transmit(&g_uart1_handle,cmd,1,10);
cmd++;
}
return 1;
}
void Send_Hex_Buff(uint8_t* buff)
{
uint8_t i=0;
while(*buff!='\0')
{
USART2_SendByte(*buff);
printf("%x",*buff);
buff++;
}
}
//自动注册指纹需要传入两字节ID号和一字节录入的次数
uint8_t PS_AutoEnroll(uint16_t ID,uint8_t number)
{
uint8_t i=6;
uint16_t sum;
PS_AutoEnrollBuffer[10]=ID>>8;
PS_AutoEnrollBuffer[11]=ID;//两个字节录入ID
PS_AutoEnrollBuffer[12]=number;//一字节录入的次数
PS_AutoEnrollBuffer[13]=0xff;
PS_AutoEnrollBuffer[14]=0x33;//两字节参数
for(;i<=14;i++)
{
sum=sum+PS_AutoEnrollBuffer[i];
}
PS_AutoEnrollBuffer[15]=sum>>8;
PS_AutoEnrollBuffer[16]=sum;
Send_Cmd(PS_AutoEnrollBuffer,17);
}
在主函数中,要加这两行代码,还有后面的发送注册的代码
这样子数据就有了,所以在接收大量数据的时候最好用第二种方式。这东西也是卡我好几天了不是串口打印有异常就是数据打印少数据