` 本帖最后由 yinwuqing 于 2021-5-31 12:16 编辑
经前段时间对XPC-3399Pro的软硬件基本功能的检测,并未突出其性能优势。据说该方案在图形数据处理方面有很大的竞争优势,而事实如何呢?因此将XPC-3399Pro接入到公司的鉴别仪创新项目上,看看视频会不会延迟吧。
首先有必要介绍一下该项目的背景,项目研发的产品主要是应用在各商业银行或中国人民银行的直属鉴定机构,将各类疑似假币的钞票置于设备中,然后在各种灯源的场景下进行拍摄,然后可以通过真币库对比,人为判断是否为真。亦可在上位机做图像处理,与存储好的样版图片进行对比,如发现异常则报假钞,提示在什么灯源下图像不正常。然后可通过局部摄像机或外接细微摄像机放大采集某部位的异常,并将采集的异常图片导出,生成PDF鉴定报告,邮件上报或直接打印。
项目整体应用框图如下,由于该项目属于公司在研项目,有些内容不便分享告知,还望理解。
该项目在全志平台上开发过,基本功能已经实现,唯独是整机测试时,使用我们开发的安卓app读视频流时会存在很大延时,大概在5秒以上,因此让客户无法接受。之前的7寸安卓屏如下:
使用了金属合叶固定在设备上
由于没有提供触摸屏,因此调试起来比较费劲。下位机MCU采用的是 STM32F103C8T6,完全满足GPIO外设的需求。灯光控制指令通过点触安卓平板上的图标触发,通过TTL串口通讯接口下发给下位机MCU,MCU再解析指令包,进行GPIO外设控制。设备在PC端已经通讯正常,标记串口信号线。当然设备还支持硬件按钮进行灯源切换。
XPC-3399Pro板上可支持配置出2个TTL。Debug接口处是需要外接调试模块,并将其设置成TTL模式,与PC端相连通打印log使用的。配置2个TTL主要通过J7、J8、J9的跳线连接来设置的,具体见《XPC-3399Pro Hardware User Manual》文档的第27页、第28页。
由于引出的插针间隙并不是标准的2.54mm,因此只能借助官方提供的转接座,然后拆卸九针接口,J7、J8、J9也重新连接跳线帽,改装如下图所示:
因此搭建了通过TTL接口直接与STM32 开发板上的串口相连,也许到这里会有坛友疑惑,为啥要用TTL 通信呢,使用USB接口通信多好。当时是考虑到USB负责摄像头500万图像的读取,如果再掺杂控制信号,会不会影响其实时性。其实是多虑了,实际上是完全可以通过USB或USB转串口方式与下位机通讯的,由于Android这边仅开发了基于串口通信的app,因此才需要改接线路。
这样直接连通似乎还少道工序,在XPC-3399Pro中安装了串口调试工具,打开软件就提示并未发现串口设备。
然后改换成USB转串口的方式了,串口工具直接显示连接的串口设备名。由于使用的串口调试工具总是自动横屏,因此不便于查看、操作,如果接了触摸屏就不存在这样的不便了。换了另一个串口调试工具,界面竖屏,方便操作。
此项目使用的串口指令见下图:
串口工具的输入还是没那么方便,为了更好得操作,安装了百度输入法,但修改下一条指令中的某个字节,又得重头开始输入,否则修改的字节会自动添加到指令后,并将所有字节往前挪一位,这是什么情况?不知是否是烧录的android8.1系统的问题还是串口工具的问题,无赖之下只好用复制粘贴的办法。演示操作如下所示:
https://v.youku.com/v_show/id_XNTE2MjMxMTQxNg==.html
https://v.youku.com/v_show/id_XNTE2MjMxMTQxNg==.html
如果采用TTL串口直接连通,手册中提到使用ADB命令行工具,ADB可分为两类:网络ADB与USB ADB,后续进入开发者模式,adb root(获取root权限)后再重装串口工具试试,这样上位机就无需更改串口通信接口代码了。
下位机基于STM32F103方案,部分代码展示如下:
- #include "stm32f10x.h"
- #include "bsp_usart.h"
- #include "bsp_led.h"
- #include "bsp_key.h"
- #include "timer.h"
- #include "delay.h"
- #include
- uint8_t key_flag=0;//按键切换摄像头标志位
- uint8_t MG_flag=0;//是否打开磁头开关
- uint8_t output[20]={0};
- int main(void)
- {
-
- SysTick_Init();
- /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
- USART_Config();
- /* LED端口初始化 */
- LED_GPIO_Config();
- /* 按键端口初始化 */
- Key_GPIO_Config();
- TIM2_Int_Init(5000, 7199);
-
- Delay_ms(8);
- GPIO_SetBits(GPIOB,GPIO_Pin_7);
- GPIO_SetBits(GPIOB,LED8_GPIO_PIN); //关绿灯
- GPIO_SetBits(GPIOB,MG_GPIO_PIN);
- GPIO_SetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红光
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- while(1)
- {
- if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )//顶白光
- {
- GPIO_SetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红光
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
-
- }
- if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )//顶紫外
- {
- GPIO_SetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红外
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- }
-
- if( Key_Scan(KEY3_GPIO_PORT,KEY3_GPIO_PIN) == KEY_ON )//顶红外
- {
- GPIO_SetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红外
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- }
-
- if( Key_Scan(KEY4_GPIO_PORT,KEY4_GPIO_PIN) == KEY_ON )//背白光
- {
- GPIO_SetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红外
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- }
-
- if( Key_Scan(KEY5_GPIO_PORT,KEY5_GPIO_PIN) == KEY_ON )//背红外
- {
- GPIO_SetBits(GPIOA,LED5_GPIO_PIN);//背红外
- GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- }
-
- if( Key_Scan(KEY6_GPIO_PORT,KEY6_GPIO_PIN) == KEY_ON )//侧白光
- {
- GPIO_SetBits(GPIOB,LED6_GPIO_PIN);//侧白光;
- GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红外
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- }
-
- if( Key_Scan(KEY7_GPIO_PORT,KEY7_GPIO_PIN) == KEY_ON )//侧红外
- {
- GPIO_SetBits(GPIOB,LED7_GPIO_PIN);//侧红外
- GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);//顶白光
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);//顶紫外
- GPIO_ResetBits(GPIOB,LED3_GPIO_PIN);//顶红外
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);//背白光
- GPIO_ResetBits(GPIOA,LED5_GPIO_PIN);//背红外
- GPIO_ResetBits(GPIOB,LED6_GPIO_PIN);//侧白光
- }
-
- if( Key_Scan(KEY8_GPIO_PORT,KEY8_GPIO_PIN) == KEY_ON )
- {
- MG_flag=~MG_flag;
- }
- if(MG_flag != 0)
- {
- GPIO_SetBits(GPIOB,LED8_GPIO_PIN); //PB4点亮绿灯
- if(SET == GPIO_ReadInputDataBit(GPIOB,MG_GPIO_PIN)) //PB9磁头闸门
- {
- GPIO_ResetBits(GPIOB,GPIO_Pin_7);
- }
- else
- {
- GPIO_SetBits(GPIOB,GPIO_Pin_7); //PB7控制磁头开关
- }
- }
- else
- {
- GPIO_ResetBits(GPIOB,LED8_GPIO_PIN);
- GPIO_ResetBits(GPIOB,GPIO_Pin_7);
- }
-
- if( Key_Scan(KEY9_GPIO_PORT,KEY9_GPIO_PIN) == KEY_ON )//拍照
- {
- memset(output,0,12);
- output[0]=0xAA;
- output[1]=0x09;
- output[2]=0x00;
- output[3]=0x00;
- output[4]=0x00;
- output[5]=0x00;
- output[6]=0x00;
- output[7]=0x00;
- output[8]=0x00;
- output[9]=0x00;
- output[10]=0x01;
- output[11]=0xB4;
- Usart_SendArray(USART2,output,12);
- }
- if( Key_Scan(KEY10_GPIO_PORT,KEY10_GPIO_PIN) == KEY_ON )//摄像机
- {
- switch(key_flag)
- {
- case 0:
- key_flag=1;
- memset(output,0,6);
- output[0]=0xAB;
- output[1]=0x03;
- output[2]=0x01;
- output[3]=0x00;
- output[4]=0x00;
- output[5]=0xAF;
- Usart_SendArray(USART2,output,6);
- break;
- case 1:
- key_flag=2;
- memset(output,0,6);
- output[0]=0xAB;
- output[1]=0x03;
- output[2]=0x00;
- output[3]=0x01;
- output[4]=0x00;
- output[5]=0xAF;
- Usart_SendArray(USART2,output,6);
- break;
- case 2:
- key_flag=0;
- memset(output,0,6);
- output[0]=0xAB;
- output[1]=0x03;
- output[2]=0x00;
- output[3]=0x00;
- output[4]=0x01;
- output[5]=0xAF;
- Usart_SendArray(USART2,output,6);
- break;
- default:
- break;
-
- }
-
- }
- RX_Data(USART_RX_BUF);
- }
- }
复制代码
- void USART2_IRQHandler(void)
- {
- if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
- {
- USART_ClearITPendingBit(USART2, USART_IT_RXNE);
- USART_TEMP_BUF[USART_RX_LEN++]=USART_ReceiveData(USART2);
- TIM_Cmd(TIM2, ENABLE);
-
- if(USART_TEMP_BUF[0]==0xAA && USART_RX_LEN==12)
- {
- TIM_Cmd(TIM2, DISABLE);
- memcpy(USART_RX_BUF,USART_TEMP_BUF,12);
- memset(USART_TEMP_BUF,0,sizeof(USART_TEMP_BUF));
- USART_RX_LEN=0;
- USART_RX_STA=1;
- }
- else if(USART_RX_LEN >=12)
- {
- memset(USART_TEMP_BUF,0,sizeof(USART_TEMP_BUF));
- USART_RX_LEN=0;
- }
- }
- }
- void RX_Data(uint8_t *data)
- {
- uint8_t output[20]={0};
- uint16_t checkcode=0,i=0,num=0;
- static uint8_t envet_flag = 0;
-
- if((USART_RX_STA&0x0001)==0)//未接收到数据,直接返回
- {
- return;
- }
- else
- {
- USART_RX_STA=0;
- Delay_ms(5);
- }
- if(data[0] == 0xAA)
- {
- num=0;
- for(i=0;i<11;i++)
- {
- num +=data[i];
- }
- checkcode = num & 0xFF;
-
- if(checkcode == data[11]) //验证校验码
- {
- checkcode_flag = 1; //校验成功
- }
-
- if(checkcode_flag == 1)
- {
-
- checkcode_flag=0;
-
- if(data[2]== 1)
- {
- envet_flag = 1;
- GPIO_SetBits(GPIOB, LED1_GPIO_PIN);
- }
- else if(data[2] == 0)
- {
- GPIO_ResetBits(GPIOB, LED1_GPIO_PIN);
- }
- if(data[3] == 1)
- {
- envet_flag = 2;
- GPIO_SetBits(GPIOB, LED2_GPIO_PIN);
- }
- else if(data[3] == 0)
- {
- GPIO_ResetBits(GPIOB,LED2_GPIO_PIN);
- }
-
- if(data[4] == 1)
- {
- envet_flag = 3;
- GPIO_SetBits(GPIOB, LED3_GPIO_PIN);
- }
- else if(data[4] == 0)
- {
- GPIO_ResetBits(GPIOB, LED3_GPIO_PIN);
- }
-
- if(data[5] == 1)
- {
- envet_flag = 4;
- GPIO_SetBits(GPIOA,LED4_GPIO_PIN);
- }
- else if(data[5] == 0)
- {
- GPIO_ResetBits(GPIOA,LED4_GPIO_PIN);
- }
-
- if(data[6] == 1)
- {
- envet_flag = 5;
- GPIO_SetBits(GPIOA, LED5_GPIO_PIN);
- }
- else if(data[6] == 0)
- {
- GPIO_ResetBits(GPIOA, LED5_GPIO_PIN);
- }
-
- if(data[7] == 1)
- {
- envet_flag = 6;
- GPIO_SetBits(GPIOB, LED6_GPIO_PIN);
- }
- else if(data[7] == 0)
- {
- GPIO_ResetBits(GPIOB, LED6_GPIO_PIN);
- }
-
- if(data[8] == 1)
- {
- envet_flag = 7;
- GPIO_SetBits(GPIOB, LED7_GPIO_PIN);
- }
- else if(data[8] == 0)
- {
- GPIO_ResetBits(GPIOB,LED7_GPIO_PIN);
- }
-
- if(data[9] == 1)
- {
- MG_flag=~MG_flag;
- if(envet_flag == 1)
- {
- GPIO_SetBits(GPIOB, LED1_GPIO_PIN);
- }
- else if(envet_flag == 2)
- {
- GPIO_SetBits(GPIOB, LED2_GPIO_PIN);
- }
- else if(envet_flag == 3)
- {
- GPIO_SetBits(GPIOB, LED3_GPIO_PIN);
- }
- else if(envet_flag == 4)
- {
- GPIO_SetBits(GPIOA,LED4_GPIO_PIN);
- }
- else if(envet_flag == 5)
- {
- GPIO_SetBits(GPIOA, LED5_GPIO_PIN);
- }
- else if(envet_flag == 6)
- {
- GPIO_SetBits(GPIOB, LED6_GPIO_PIN);
- }
- else if(envet_flag == 7)
- {
- GPIO_SetBits(GPIOB, LED7_GPIO_PIN);
- }
-
- if(MG_flag != 0)
- {
- GPIO_SetBits(GPIOB,LED8_GPIO_PIN); //PB4点亮绿灯
-
- if(SET == GPIO_ReadInputDataBit(GPIOB,MG_GPIO_PIN)) //PB9磁头闸门
- {
- GPIO_ResetBits(GPIOB,GPIO_Pin_7);
- }
- else
- {
- GPIO_SetBits(GPIOB,GPIO_Pin_7); //PB7控制磁头开关
- }
- }
- else
- {
- GPIO_ResetBits(GPIOB,LED8_GPIO_PIN);
- GPIO_ResetBits(GPIOB,GPIO_Pin_7);
- }
- }
- else if(data[9] == 0)
- {
- GPIO_ResetBits(GPIOB,LED8_GPIO_PIN);
- GPIO_ResetBits(GPIOB,GPIO_Pin_7);
- }
-
- memset(output,0,4);
- output[0]=0xAA;
- output[1]=0x01;
- output[2]=0x00;
- output[3]=0xAB;
-
- Usart_SendArray(USART2,output,4);
- }
- else
- {
- memset(output,0,4);
- output[0]=0xAA;
- output[1]=0x01;
- output[2]=0x01;
- output[3]=0xAC;
-
- Usart_SendArray(USART2,output,4);
-
- }
- }
- }
复制代码
- #include
- #include "timer.h"
- #include "bsp_usart.h"
- extern u8 USART_TEMP_BUF[USART_REC_LEN];
- extern u8 USART_RX_LEN;
- void TIM2_Int_Init(u16 arr, u16 psc)
- {
- TIM_TimeBaseInitTypeDef TIM_Time2BaseStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
- TIM_Time2BaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
- TIM_Time2BaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值
- TIM_Time2BaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
- TIM_Time2BaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseInit(TIM2, &TIM_Time2BaseStructure); //根据指定的参数初始化TIMx的时间基数单位
- TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能指定的TIM3中断,允许更新中断
- //中断优先级NVIC设置
- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
- NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
- TIM_Cmd(TIM2, DISABLE); //关闭TIM2
- }
- ////定时器2中断服务程序
- void TIM2_IRQHandler(void) //TIM2中断
- {
- if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查TIM2更新中断发生与否
- {
- TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIMx更新中断标志
- memset(USART_TEMP_BUF,0,sizeof(USART_TEMP_BUF));
- USART_RX_LEN=0;
- TIM_Cmd(TIM2, DISABLE);
- }
- }
复制代码
此设备结合PC端鉴定软件,运行稳定,已受广大客户的一致好评,之所以需要搭建在Android平板下,是为了更方便地操作,而且有些客户电脑的USB使用受限制或者接口老化,易接触不良,设备配专属的平板,更具竞争优势。目前设备可支持多种钞票的鉴别,也可推向票据市场。币种举例如下图:
|