演示视频:https://www.bilibili.com/video/BV1tC411n7x8/
代码汇总
主函数
查询网上的添加指纹的代码,进入不了状态机,后按照江科大的状态机写法,修改的代码。目前只能添加一个指纹。
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "OLED.h"
#include "Timer.h"
#include "Serial.h"
#include "as608.h"
#include "usart2.h"
#include "sys.h"
#include "Servo.h"
#include "Key.h"
SysPara AS608Para;//指纹模块AS608参数
u16 ValidN;//模块内有效指纹个数
void press_FR(void);//刷指纹
void Add_FR(void);
void Del_FR(void);
int main(void)
{
uint8_t KeyNum;
myLED_Init();
Servo_Init();
// Servo_SetAngle(180);
Servo_SetAngle(0);
OLED_Init();
PS_StaGPIO_Init();//初始化PA6读状态引脚
Serial_Init();
usart2_init();
Key_Init();
while(1)
{
//Servo_SetAngle(60);
// Del_FR();
LED_OFF();
OLED_ShowString(1,1,"NUM:");
KeyNum = Key_GetNum();
OLED_ShowNum(1,5,KeyNum,2);
Delay_ms(100);
// OLED_Clear();
if(KeyNum)
{
if(KeyNum==1)
{
Add_FR();
}
// else
// {
// OLED_ShowString(2,1,"hhh");
// Delay_ms(500);
// }
}
if(KeyNum==2)
{
Del_FR();
}
Del_FR();
if(PS_Sta)
{
press_FR();
}
}
}
//刷指纹
void press_FR(void)
{
SearchResult seach;
u8 ensure;
OLED_Clear();
OLED_ShowString(1,1,"Press Finger");
ensure=PS_GetImage();
if(ensure==0x00)//获取图像成功
{
ensure=PS_GenChar(CharBuffer1);
if(ensure==0x00) //生成特征成功
{
ensure=PS_HighSpeedSearch(CharBuffer1,0,300,&seach);
if(ensure==0x00)//搜索成功
{
OLED_Clear();
OLED_ShowString(1,1,"Find Finger");
LED_ON();
Servo_SetAngle(60);
}
else
{
OLED_Clear();
OLED_ShowString(1,1,"Unknow Finger");//未搜索到指纹
}
}
else
OLED_ShowString(1,1,"creat fail");//生成失败
Delay_ms(600);
}
OLED_Clear();
}
void Add_FR(void)
{
uint8_t ID,i,ensure,processnum = 0;
while(1)
{
if(processnum == 0)
{
i++;
OLED_Clear();
OLED_ShowString(1,1,"Put Finger");
ensure = PS_GetImage();
if(ensure == 0x00)
{
ensure = PS_GenChar(CharBuffer1);
if(ensure == 0x00)
{
OLED_Clear();
OLED_ShowString(1,1,"Finger OK");
i=0;
processnum=1;//跳到第二步
}
else
{
OLED_ShowString(2,1,"err");
}
}
else
{
OLED_ShowString(2,1,"err");
}
}
else if(processnum == 1)
{
i++;
OLED_Clear();
OLED_ShowString(1,1,"Finger Again");//请在按一次
ensure=PS_GetImage();
if(ensure==0x00)
{
ensure = PS_GenChar(CharBuffer2);
if(ensure == 0x00)
{
OLED_Clear();
OLED_ShowString(1,1,"Finger OK");
i=0;
processnum=2;//跳到第三步
}
else
{
OLED_ShowString(2,1,"err");
}
}
else
{
OLED_ShowString(2,1,"err");
}
}
else if(processnum == 2)
{
OLED_Clear();
OLED_ShowString(1,1,"Fing Comper");//对比两次指纹
ensure=PS_Match();
if(ensure == 0x00)
{
OLED_Clear();
OLED_ShowString(1,1,"Match-Ok");//对比成功,两次指纹一样
processnum=3;//跳到第四步
}
else
{
OLED_Clear();
OLED_ShowString(1,1,"Match No");//对比失败
OLED_ShowString(2,1,"Back 1");//重新录入指纹
i=0;
processnum=0;//跳回第一步
}
Delay_ms(600);
}
else if (processnum == 3)
{
OLED_Clear();
OLED_ShowString(1,1,"Creat Mode");//生成指纹模板
ensure=PS_RegModel();
if(ensure==0x00)
{
OLED_Clear();
OLED_ShowString(1,1,"Creat Success");//生成指纹模板成功
processnum=4;//跳到第五步
}
else
{
processnum = 0;
OLED_ShowString(2,1,"err");
}
Delay_ms(600);
}
else if(processnum == 4)
{
OLED_Clear();
ID = 0x01;
ensure=PS_StoreChar(CharBuffer2,ID);//储存模板
if(ensure == 0x00)
{
OLED_Clear();
OLED_ShowString(1,1,"Add ok");//录入指纹成功
Delay_ms(600);
break;
}
else
{
processnum=0;
OLED_ShowString(1,1,"Add no");
Delay_ms(600);
break;
}
}
}
}
//删除指纹
void Del_FR(void)
{
u8 ensure;
u16 num;
OLED_Clear();
OLED_ShowString(1,1," del finger");//删除指纹
OLED_ShowString(2,1," input id");//请输入指纹ID按Enter发送
Delay_ms(50);
ensure=PS_Empty();//清空指纹库
if(ensure==0)
{
OLED_Clear();
OLED_ShowString(1,1,"del sucess");//删除指纹成功
}
else
{
OLED_Clear();
OLED_ShowHexNum(1,1,ensure,4);
}
Delay_ms(500);
PS_ValidTempleteNum(&ValidN);//读库指纹个数
OLED_ShowNum(1,1,AS608Para.PS_max-ValidN,4);
}
as608.c与as608.h的代码网上很多,本文就不放了
usart2代码
usart2.c
#include "stm32f10x.h"
#include "usart2.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
#include "Timer.h"
#include "Delay.h"
//串口接收缓存区
uint8_t USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN个字节.
uint8_t USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 USART2_RX_STA=0;
void USART2_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据
{
res =USART_ReceiveData(USART2);
if((USART2_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
{
if(USART2_RX_STA<USART2_MAX_RECV_LEN) //还可以接收数据
{
TIM_SetCounter(TIM3,0);//计数器清空 //计数器清空
if(USART2_RX_STA==0) //使能定时器2的中断
{
TIM_Cmd(TIM3,ENABLE);//使能定时器2
}
USART2_RX_BUF[USART2_RX_STA++]=res; //记录接收到的值
}else
{
USART2_RX_STA|=1<<15; //强制标记接收完成
}
}
}
}
//初始化IO 串口2
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率
void usart2_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //串口2时钟使能
USART_DeInit(USART2); //复位串口2
//USART2_TX PA2
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
//USART2_RX PA3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PA3
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 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(USART2, &USART_InitStructure); //初始化串口2
USART_Cmd(USART2, ENABLE); //使能串口
//使能接收中断
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//设置中断优先级
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
Timer_Init(); //10ms中断
USART2_RX_STA=0; //清零
TIM_Cmd(TIM3,DISABLE); //关闭定时器2
}
//串口2,printf 函数
//确保一次发送数据不超过USART2_MAX_SEND_LEN字节
void u2_printf(char* fmt,...)
{
u16 i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART2_TX_BUF,fmt,ap);
va_end(ap);
i=strlen((const char*)USART2_TX_BUF); //此次发送数据的长度
for(j=0;j<i;j++) //循环发送数据
{
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
USART_SendData(USART2,USART2_TX_BUF[j]);
}
}
usart2.h
#ifndef __USART2_H
#define __USART2_H
#include "sys.h"
#define USART2_MAX_RECV_LEN 400 //最大接收缓存字节数
#define USART2_MAX_SEND_LEN 400 //最大发送缓存字节数
#define USART2_RX_EN 1 //0,不接收;1,接收.
extern u8 USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern vu16 USART2_RX_STA; //接收数据状态
void usart2_init(void);//串口2初始化
void u2_printf(char* fmt,...);
#endif
定时器代码
Timer.c
#include "stm32f10x.h" // Device header
extern uint16_t USART2_RX_STA;
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
USART2_RX_STA|=1<<15; //标记接收完成
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_Cmd(TIM3, DISABLE); //关闭TIM7
}
}
Timer.h
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif
本文其他代码则使用的是江科大的代码
遇见的问题汇总
一 as608与单片机连接失败(即握手失败)
as608的波特率不是9600,可通过下面这个链接修改as608的波特率
http://t.csdnimg.cn/batia
二定时器选用问题
1.as608和舵机都需要使用定时器,不能重复,且要根据自己使用的单片机型号,选择舵机的引脚,对应的引脚定时器可以控制pwm输出信号。