stm32cubeMX学习十、扫码模块程序开发(基于正点原子STM32F407开发板)

本程序编写基于正点原子STM32F407开发板。
在这里插入图片描述
本文使用的扫码模块是下面这个品牌。
在这里插入图片描述
扫码模块的应用场景非常广泛,我们可以上百度搜索一下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
等等。
今天就来说说如何在开发板上实现控制它吧,打开数据手册看引脚配置。
在这里插入图片描述
该模块是基于串口开发,本例程只接了上述的5个引脚,其余的没有接入。
按手册提供的说明,只要我们每次扫码之前将nTrig管脚拉低,即可激活扫码模块,我们先接上Uart测试下效果,在没有接nTrig脚的时候,是下面这个样子,此时为非扫码模式。
在这里插入图片描述
当将nTrig引脚接地时,是下面这个样子,此时扫码模式激活,只需随便拿一个条码接近光源就可以得到数据输出。
在这里插入图片描述
关于模块的详细配置信息,可以参考数据手册:LV3096集成手册。
https://download.csdn.net/download/morixinguan/11603322
接下来开始配置CubeMX,驱动这个模块。

一、配置IO和串口以及OS

1.1、配置普通IO

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中PE0就是图中的nTrig引脚,PE3为按键,当按键按下时,触发nTrig引脚为低电平。
PF8为蜂鸣器,即成功收到扫码模块返回的数据后,会一声,PF9和PF10为指示灯。

1.2、配置串口

串口2用来打印信息。
在这里插入图片描述
串口3是扫码模块,根据手册提示,该模块的默认波特率为9600。
在这里插入图片描述
配置全局中断。
在这里插入图片描述

1.3、配置FreeRtos

由于我的项目需要带OS,所以顺便也把OS配置上吧,把软件定时器勾上,其它的选项默认即可。
在这里插入图片描述
注意,配置了FreeRtos,要把这里的时钟源改掉,以免冲突。
在这里插入图片描述

1.4、配置时钟

默认配置为168MHz
在这里插入图片描述

1.5、生成代码

在这里插入图片描述

二、编写相关逻辑

在main.c中添加头文件

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* USER CODE END Includes */

在main.c中定义任务和信号量

/* USER CODE BEGIN PV */
//判断当前是否在OS
__IO int start_os = 0;	
//扫码任务
osThreadId ScanTaskHandle;
//按键任务
osThreadId KeyTaskHandle;
//得到扫码数据的信号量
SemaphoreHandle_t  Scan_Data_Semaphore = NULL;
/* USER CODE END PV */

在main.c中定义串口打印函数和任务函数

/* USER CODE BEGIN PFP */
//扫码任务处理
void StartKeyTask(void const * argument);
//按键任务处理
void StartScanTask(void const * argument);
//定义printf的重定向函数fputc,满足串口调试打印
int fputc(int ch, FILE* file)
{
    HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 1000);
    return ch;
}
/* USER CODE END PFP */

在stm32f4xx_hal_msp.c中串口三的用户定义区域使能串口3接收中断。

  /* USER CODE BEGIN USART3_MspInit 1 */
  //这里不需要发送
 __HAL_UART_DISABLE_IT(huart, UART_IT_TC);
  __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
  /* USER CODE END USART3_MspInit 1 */

在stm32f4xx_it.c中编写中断服务函数
定义串口接收缓存以及计数变量。

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t scan_rx_count;
uint8_t USART3_RX_BUF[UART_RECV_LEN] = {0} ;
/* USER CODE END PV */

编写扫码模块串口中断服务函数

/**
  * @brief This function handles USART3 global interrupt.
  */
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
    //加热器串口中断服务函数
    uint32_t ulReturn;
    uint8_t Res;
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    //进入临界段,不可被中断
    if(1 == start_os)
        ulReturn = taskENTER_CRITICAL_FROM_ISR();

    if((__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
        HAL_UART_Receive(&huart3, &Res, 1, 1000);

        if('\n' != Res)
        {
            USART3_RX_BUF[scan_rx_count++] = Res ;
        }
        else
        {
            //如果接收的是\n,则上一个接收的数据为'\r'结束
            if('\r' == USART3_RX_BUF[scan_rx_count - 1])
            {
                //添加结束符
                USART3_RX_BUF[scan_rx_count - 1] = 0x00 ;
                //接收计数清0
                scan_rx_count = 0 ;

                //给出一个信号量
                if(1 == start_os)
                    xSemaphoreGiveFromISR(Scan_Data_Semaphore, &xHigherPriorityTaskWoken);
            }
        }
    }

  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */
    //退出临界段
    if(1 == start_os)
        taskEXIT_CRITICAL_FROM_ISR( ulReturn );

  /* USER CODE END USART3_IRQn 1 */
}

在main.c中创建信号量和任务函数
创建信号量

 //创建一个二值信号量,用于传感器数据的接收处理
  Scan_Data_Semaphore = xSemaphoreCreateBinary();
  assert_param(NULL != Scan_Data_Semaphore);

创建任务函数

/* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  osThreadDef(ScanTask, StartScanTask, osPriorityNormal, 0, 128);
  ScanTaskHandle = osThreadCreate(osThread(ScanTask), NULL);
  
  osThreadDef(KeyTask, StartKeyTask, osPriorityNormal, 0, 128);
  KeyTaskHandle = osThreadCreate(osThread(KeyTask), NULL);
  /* USER CODE END RTOS_THREADS */

编写应用逻辑

/* USER CODE BEGIN 4 */
//按键处理任务
void StartKeyTask(void const * argument)
{
	while(1)
	{
		//当按键按下时候,触发扫码模块
		if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin))
			HAL_GPIO_WritePin(START_SCAN_GPIO_Port, START_SCAN_Pin, GPIO_PIN_RESET);
		osDelay(200);
	}
}

extern uint8_t scan_rx_count;
extern uint8_t USART3_RX_BUF[UART_RECV_LEN] ;
//扫码处理任务
void StartScanTask(void const * argument)
{
	start_os = 1 ;
	BaseType_t xResult;
    uint8_t *__Scan_Data_Cpy = NULL ;
    __Scan_Data_Cpy = malloc(UART_RECV_LEN);
    assert_param(NULL != __Scan_Data_Cpy);
	while(1)
    {
        //等待获取一个信号量,portMAX_DELAY表示无超时限制
        xResult = xSemaphoreTake(Scan_Data_Semaphore, portMAX_DELAY);
        if(xResult == pdTRUE)
        {
            memset(__Scan_Data_Cpy, 0, UART_RECV_LEN);
            memcpy(__Scan_Data_Cpy, USART3_RX_BUF, strlen((char *)USART3_RX_BUF));
			printf("扫码数据:%s\n",__Scan_Data_Cpy);
			memset(USART3_RX_BUF,0,UART_RECV_LEN);
			//关闭扫码使能
			HAL_GPIO_WritePin(START_SCAN_GPIO_Port, START_SCAN_Pin, GPIO_PIN_SET);
			//蜂鸣器鸣叫一声
			HAL_GPIO_WritePin(BELL_GPIO_Port,BELL_Pin,GPIO_PIN_SET);
			osDelay(150);
			HAL_GPIO_WritePin(BELL_GPIO_Port,BELL_Pin,GPIO_PIN_RESET);
        }
    }
}
/* USER CODE END 4 */

三、运行结果

按下按键KEY1激活扫码模块
在这里插入图片描述
拿一个有条码的本子
在这里插入图片描述
靠近扫码枪,识别到条形码后,扫码枪会将光源关断,如需要再次使用,需要再按下KEY1按键开启。
在这里插入图片描述
串口收到的打印结果,和本子上的条形码的数据是一样的。
在这里插入图片描述
Demo例程,后续提供。

发布了597 篇原创文章 · 获赞 1061 · 访问量 182万+

猜你喜欢

转载自blog.csdn.net/morixinguan/article/details/100036476