找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2594|回复: 0
打印 上一主题 下一主题
收起左侧

STM32单片机+GM65二维码识别源程序

[复制链接]
跳转到指定楼层
楼主
ID:949309 发表于 2022-4-28 15:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include "delay.h"
#include "usart3.h"
#include "stdarg.h"                  
#include "stdio.h"                  
#include "string.h"         
#include "timer.h"
#include "lcd.h"
#include "usart.h"   

//串口接收缓存区         
u8 USART3_RX_BUF[USART3_MAX_RECV_LEN];                                 //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
u8  USART3_TX_BUF[USART3_MAX_SEND_LEN];                         //发送缓冲,最大USART3_MAX_SEND_LEN字节

//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 USART3_RX_STA=0;           
        u16 i;
        u16 check;
        u8 uart3_len=0; //数据长度,uart3_len+1加上帧尾
        u8 x=0;
        u8 RxCounter1=0;
        u8 RxBuffer1[20]={0};
    u8 RxState = 0;        

//USART1 全局中断服务函数


//初始化IO 串口3
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率         
void usart3_init(u32 bound)
{  

        NVIC_InitTypeDef NVIC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);        // GPIOB时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能

         USART_DeInit(USART3);  //复位串口3
                 //USART3_TX   PB10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10

    //USART3_RX          PB11
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11
        
        USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式

        USART_Init(USART3, &USART_InitStructure); //初始化串口        3


        USART_Cmd(USART3, ENABLE);                    //使能串口
        
        //使能接收中断
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
        
        //设置中断优先级
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
        
        
        TIM7_Int_Init(99,7199);                //10ms中断
        USART3_RX_STA=0;                //清零
        TIM_Cmd(TIM7,DISABLE);                        //关闭定时器7

}




unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{
                unsigned short wCRCin = 0x0000;
                unsigned short wCPoly= 0x1021;
                unsigned char wChar = 0;
                while (usDataLen--)
                {
                        wChar = *(puchMsg++);//4,1 3,2 3,3, 1,4 1,5
                        wCRCin ^=(wChar << 8);
                                
                        for( i = 0; i< 8; i++)
                   {        
                                if(wCRCin & 0x8000)
                                {
                                   wCRCin =(wCRCin << 1) ^ wCPoly;
                                }
                                else
                                {
                                    wCRCin = wCRCin << 1;
                                }

                        
                   }
       }
                        return(wCRCin);   
}

void USART3_IRQHandler(void)                     
{

               


                if( USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET)             //接收中断  
                {
                                USART_ClearITPendingBit(USART3,USART_IT_RXNE);   //清除中断标志
                                RxBuffer1[RxCounter1++] = USART_ReceiveData(USART3);
                        

                }


               
                if(RxBuffer1[RxCounter1-1]==13) //0x0D
                {
                        uart3_len=RxCounter1-1;
               
                        check=CRC16_XMODEM(&RxBuffer1[RxCounter1],uart3_len+1);   //校验和(crc)
                        if(((check&0x00ff)==RxBuffer1[uart3_len+1])&&(((check>>8)&0x00ff)==RxBuffer1[uart3_len+1]))
                        {
                                RxState=1;
                                                        
                        }
        
                        
                }
               
               
               
               
if(USART_GetFlagStatus(USART3,USART_FLAG_ORE) == SET) //判断中断是否溢出
    {
      USART_ClearFlag(USART3,USART_FLAG_ORE);
      USART_ReceiveData(USART3);
    }
        
        if(RxState)
        {
                for(x=0;x<uart3_len+1;x++)
                {USART_SendData(USART1,RxBuffer1[x]);
                delay_ms(10);}

                RxState=0;
                RxCounter1=0;
               
        }
               
               
               
               
}


//串口3,printf 函数
//确保一次发送数据不超过USART3_MAX_SEND_LEN字节
//void u3_printf(char* fmt,...)  
//{  
//        u16 i,j;
//        va_list ap;
//        va_start(ap,fmt);
//        vsprintf((char*)USART3_TX_BUF,fmt,ap);
//        va_end(ap);
//        i=strlen((const char*)USART3_TX_BUF);                //此次发送数据的长度
//        for(j=0;j<i;j++)                                                        //循环发送数据
//        {
//          while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   
//                USART_SendData(USART3,USART3_TX_BUF[j]);
//        }
//}


扫描过后,模块的串口通讯参数:波特率 9600bps,无校验,8 位数据位,1 位停止位,无流控。
改为串口后,所有的数据都由串口输出,也可以直接发送命令控制模块

对模块的标志位进行读操作:
发送命令格式:
{Head1} {Types} {Lens} {Address} {Datas} {CRC}
Head1 :0x7E 0x00(2 bytes)
Types    :0x07(1 byte)
Lens    :0x01(1 byte)
Address :0x0000~0x00FF(2 bytes),表示要读取的标志位的起始地址。
Datas    :0x00~0xFF(1 byte),表示要连续读取的标志位的字节数,0x00 表示 256 个字节。
CRC    :CRC_CCITT 校验值(2 bytes)。计算的范围:Types、Lens、Address、Datas。
计算的方法为 CRC_CCITT,特征多项式:X16+X12+X5+1,多项式系数为 0x1021,
初始值为全 0,对于单个字节来说最高位先计算,不需要取反直接输出。
注:当用户不需要 CRC 校验功能时,可在 CRC 字节处填写 0xAB 0xCD,免校验。

接收到数据格式:
1:如果模块成功数据并且成功返回
{Head2} {Types} {Lens} {Datas} {CRC}
Head2 :0x02 0x00
Types    :0x00(读成功)
Lens    :表示上传的 Datas 的字节个数,0x00 表示 256 个
Datas    :0x00~0xFF,表示读上来的数据
CRC   : CRC_CCITT 校 验 值 。 计算的范围:Types、Lens、Datas。计算的方法为 CRC_CCITT,特征多项式:X16+X12+X5+1,多项式系数为 0x1021,初
始值为全 0,对于单个字节来说最高位先计算,不需要取反直接输出。
注:当用户不需要 CRC 校验功能时,可在 CRC 字节处填写 0xAB 0xCD,免校验。


2: 下发 CRC 校验失败
无回应命令

3:未知命令应答
无回应命令
示例:(供参考)

CRC  C 参考代码:
unsigned int crc_cal_by_bit(unsigned char* ptr, unsigned int len)
{
unsigned int crc = 0;
while(len-- != 0)
{
for(unsigned char i = 0x80; i != 0; i /= 2)
{
crc *= 2;
if((crc&0x10000) !=0) //上一位 CRC 乘 2 后,若首位是 1,则除以 0x11021
crc ^= 0x11021;
if((*ptr&i) != 0) //如果本位是 1,那么 CRC = 上一位的 CRC + 本位/CRC_CCITT
crc ^= 0x1021;
}
ptr++;
}
return crc;
}
注:当用户不需要 CRC 校验功能时,可在 CRC 字节处填写 0xAB 0xCD,免校验。

示例:
对标志位中地址为 0x000A 的 1 个地址进行读操作
1:读成功并返回数据,返回的数据为 0x3E
输入:0x7E 0x00 0x07 0x01 0x00 0x0A 0x01 0xEE 0x8A
返回:0x02 0x00 0x00 0x01 0x3E 0xE4 0xAC
2:下发的 CRC 错误
输入:0x7E 0x00 0x07 0x01 0x00 0x0A 0x01 0x11 0x22
返回:无
3:当发送的指令长度不够或发送 0x7e 0x00 后等待时间超过 400ms 时,当成未知命令处理
输入:0x7E 0x00 0x07 0x01 0x00 0x0A 0x01
返回:无



对模块标志位进行写操作:
发送命令格式:
{Head1} {Types} {Lens} {Address} {Datas} {CRC}
Head1 :0x7E 0x00(2 bytes)
Types    :0x08(1 byte)
Lens    :0x00~0xFF(1 byte),表示该命令中 Datas 字段的字节数,同时也表示要进行连续
写操作的次数,而 0x00 表示有 256 个字节
Address :0x0000~0xFFFF(2 bytes),表示要写入的标志位的起始地址
Datas    :0x00~0xFF(1~256 bytes),表示写入标志位的数据
CRC    :CRC_CCITT 校验值(2 bytes)。计算的范围:Types、Lens、Address、Datas  
注:当用户不需要 CRC 校验功能时,可在 CRC 字节处填写 0xAB 0xCD,免校验。


返回数据格式:
1:写标志位成功
{Head2} {Types} {Lens} {Datas} {CRC}
Head2 :0x02 0x00
Types    :0x00(写成功)
Lens    :0x01
Datas    :0x00
CRC    :CRC_CCITT  

2:下发 CRC 校验失败
无回应命令

3:未知命令应答
无回应命令


示例:
向地址为 0x000A 的标志位写入 0x3E
1: 设置成功
输入:0x7E 0x00 0x08 0x01 0x00 0x0A 0x3E 0x4C 0xCF
返回:0x02 0x00 0x00 0x01 0x00 0x33 0x31

2: 下发的 CRC 错误
输入:0x7E 0x00 0x08 0x01 0x00 0x0A 0x3E 0x11 0x22
返回:无

3: 当发送的指令长度不够或发送 0x7e 0x00 后等待时间超过 400ms 时,当成未知命令处理
输入:0x7E 0x00 0x08 0x01 0x00 0x0A 0x3E
返回:无



   标志位保存到 EEPROM 指令

若要将设备标志位的内容保存到外挂的 EERPOM 中则需要发送保存命令。
数据发送命令格式:
{Head1} {Types} {Lens} {Address} {Datas} {CRC}
Head1 :0x7E 0x00
Types    :0x09
Lens    :0x01
Address :0x0000
Datas    :0x00
CRC    :CRC_CCITT 校验值(0xDE 0xC8)

接收数据格式:
1:保存成功
{Head2} {Types} {Lens} {Datas} {CRC}
Head2 :0x02 0x00
Types    :0x00(写成功)
Lens    :0x01
Datas    :0x00
CRC    :CRC_CCITT 校验值(0x33 0x31)
2:下发 CRC 校验失败
无回应命令

3:未知命令应答
无回应命令

部分串口命令示例:
1:触发扫描串口指令为:7E 00 08 01 00 02 01 AB CD;识读模块收到触发指令后,会先输出七个字节的回应信息并同步启动扫描(回应信息内容:02 00 00 01 00 33 31)
2:设置模块为命令触发模式,照明灯常亮,普通瞄准,启动静音,开启解码成功LED提示
发送格式:7E 00 08 01 00 00 99 AB CD   
接收成功后返回: 02 00 01 00 33 31
3:设置模块为感应模式,照明灯关闭,瞄准常亮,关闭静音,关闭解码成功LED提示
发送格式:7E 00 08 01 00 00 63 AB CD   
接收成功后返回: 02 00 01 00 33 31
4:从标志位0X0002中读取数据,判断是否输出解码状态提示符
发送格式:7E 00 07 01 00 02 01 AB CD
接收成功后返回;02 00 00 01 40 AB CD

Keil代码等资料下载: GM65.7z (1.34 MB, 下载次数: 57)

评分

参与人数 1黑币 +40 收起 理由
admin + 40 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表