下面V3.3接VCC,引脚中的GND1和GND2中的任何一个接GNDj就行了,让后clk和data随便接个复用功能空出来的引脚就行,它这个是用模拟iic来实现这个功能的,所以引脚可以随便接下,我用的板子时stm32fzet6,clk就直接接PE4,data直接接PE5了。
外表长这样的低频卡
内部存储如下所示
它这个卡有两页,分别是1页和0页,它的1页设计是只可以读,不可以写。每个数据块都有32bit(1bit为8位)的存储空间,1页有两个数据块,但对第1页的数据块读取完32bit后,它会进入第1页的另一数据块读取32bit,然后再读32bit后,它就会回到原来的数据块重新读取。下图为第1页各数据块中存放的内容,block1为数据块1,block2为数据块2.
我们再来看下它这个第0页的,它的所有块都是可读可写的,但它的第0块数据块是用来存储设定的指令的,所以一般情况下的都是只可读的情况。同时它的指令设计为32位(即4bit),但我不知道是它手册少给了还是什么,等大伙看后面代码控制这32位指令位是注意看下就知道了,很奇怪的。
我们再来看下第0页的其他几块数据块,1到6块都是存数据的,只有第7块有所区别,在我们选择正常读和正常写时,第7块就是存放数据的,但当我们选择保护写和保护读时(即读写需要输入相应密码),第7块的前32位(4bit)即为密码。
p就表示你想选择那一页,总共有2页,当然第1页只能读,L表示锁定位,只有为0的时候才能正常读写,直接访问中的1P*后面那个0也是指锁定位,password就是密码,即32位(4bit),数据data也是32位,addr指地址,因为有7块数据块,刚好可以用3位表示,即addr用来选择数据块,如果你选择直接访问的话,你其实可以读32bit(远远于32位),可你写只能写4位就很奇怪,估计应该可以写更多的,建议大家去看下手册,也不知道后面这个能不能不看,要看的话,直接搜索Ic-T5557数据手册应该搜的出来。
非接触方式的读/写数据传输 - 豆丁网 (docin.com)
你发的这些指令读卡器是不能直接识别的,这就需要我们最开始说的模拟iic输入,但它这个是用时间长短来模拟的,就很神奇,所以感觉又和iic模拟不一样,iic是有一根时钟线,还有根数据线的,它这个再写入数据时用clk拉高的时间来确定时写入0还是1,它在读取时就用data的电平跳变来确定读取到的是0还是1,即曼彻斯特编码(Manchester)来读取。下图是如何控制写入的时间来区分0与1
首先需要将引脚初始化,读取第一页的内容不管有没有密码都是直接读的,我的printf函数是串口打印,你直接用自己的就行,要串口usart.h函数可以去我那篇lory里面找下。
lf15k.c
#include "stm32f10x.h"
#include
#include "systick.h"//这个是用于延时读卡延时的,它这个也许会和一般的delay冲突,所以等下我把delay也放过来
#include "lf125k.h"
#include "usart1.h"
/* Types -----------------------*/
/* Constants -------------------*/
/* Define ----------------------*/
#define REM GPIO_read_lf125k_data()
#define CLK(n) GPIO_set_lf125k_clk(n)
#define M_OK 0
#define LF_DBR_BASE
#define LF_1us 72ul
#define LF_720us (720000-LF_1us*720)
#define LF_650us (720000-LF_1us*650)
#define LF_Star (720000-LF_1us*5000)//5ms
#define LF_T557 (720000-LF_1us*350)//350us
#define LF_380us (720000-LF_1us*380)
#define LF_350us (720000-LF_1us*384)//8*48
//#define LF_350us (720000-LF_1us*350)
#define LF_250us (720000-LF_1us*250)
#define LF_200us (720000-LF_1us*200)
#define LF_100us (720000-LF_1us*128)//8*18
//#define LF_100us (720000-LF_1us*100)
#define LF_5ms (720000-LF_1us*5000)//5ms
//低频
#define GPIO_LF125K_DATA GPIOE
#define GPIO_LF125K_DATA_PIN GPIO_Pin_5
#define GPIO_LF125K_CLK GPIOE
#define GPIO_LF125K_CLK_PIN GPIO_Pin_4
typedef enum { //第一页块的地址,0x00就是第0块,以此类推
LF125_PAGE0_BANK0=0x00,
LF125_PAGE0_BANK1=0x01,
LF125_PAGE0_BANK2=0x02,
LF125_PAGE0_BANK3=0x03,
LF125_PAGE0_BANK4=0x04,
LF125_PAGE0_BANK5=0x05,
LF125_PAGE0_BANK6=0x06,
LF125_PAGE0_BANK7=0x07,
}LF125_PAGE0_BANKx;
/* Variables -------------------*/
/* Functions prototypes --------*/
/* Functions -------------------*/
void GPIO_LF125K_configuration(void)//GPIO引脚的初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_LF125K_CLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_LF125K_CLK, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_LF125K_DATA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIO_LF125K_DATA, &GPIO_InitStructure);
}
/*
*@brief .
*@param .
*@retval .
*/
void GPIO_set_lf125k_clk (uint8_t status)//改变clk的值
{
if (status)
GPIO_WriteBit(GPIO_LF125K_CLK, GPIO_LF125K_CLK_PIN,Bit_SET);
else
GPIO_WriteBit(GPIO_LF125K_CLK, GPIO_LF125K_CLK_PIN,Bit_RESET);
}
/*
*@brief .
*@param .
*@retval .
*/
uint8_t GPIO_read_lf125k_data (void)//读取data的值
{
return GPIO_ReadInputDataBit(GPIO_LF125K_DATA, GPIO_LF125K_DATA_PIN);
}
uint8_t volue;//volue 为曼侧斯特码译码时的临时运算缓存
uint8_t tap;//tap 为曼侧斯特码发射时的临时运算缓存
uint8_t data_tap[6];//等待发射的数据
//打开天线(这个叫法怪怪的)
void LF125K_open_RF(void)
{
CLK(1);
}
//关闭天线
void LF125K_close_RF(void)//
{
CLK(0);
}
void LF125K_init(void)//初始化引脚和打开clk
{
GPIO_LF125K_configuration();
LF125K_open_RF();
// DBG_B_INFO("LF125K初始化成功");
}
/*
*@brief Manchester process.曼侧斯特
*@param .
*@retval 0:success
1:failse.
*/
int8_t REM_Processing(uint8_t *buf)//读取8位数据,后面i值可以根据自己想要进行更改,但注意buf大小的改变
{
uint32_t i,j,delay;
long tus;
for(i=0;i<50;i++){//find the first cync head 在规定时间内获得data的一个下降沿
volue=0;
delay = 7200;
while(REM == 0 && delay)//wait high level
delay --;
if (delay == 0) {
return 1;//timeout
}
SYSTICK_ClearSystickVal();
while(REM == 1){
if(SYSTICK_GetVal() > LF_720us){
}else{
i = 50;
break;
}
}
}
delay = 7200;
while(REM == 1 && delay)//wait low level //通过两个while获得data的一个上升沿
delay --;
if (delay == 0) {
return 1;
}
delay = 72000;
while(REM == 0 && delay)//wait high level
delay --;
if (delay == 0) {
return 1;
}
SYSTICK_ClearSystickVal();
tus = LF_650us;
for(i=0;i<8;i++)//开始读取数据
{
for(j=0;j<8;j++)
{
while(SYSTICK_GetVal() > tus);
if(REM==1)//一个下降沿为一个1
{
delay = 7200;
while(REM==1 && delay){
delay --;
}
if(delay == 0)
return 1;
volue>>=1;
volue|=0x80;
tus = LF_T557;
SYSTICK_ClearSystickVal();
}
else
{
delay = 7200;
while(REM==0 && delay){//一个上升沿为一个0
delay --;
}
if(delay == 0)
return 1;
volue>>=1;
volue|=0x00;
tus = LF_T557;
SYSTICK_ClearSystickVal();
}
}
buf[i]=volue;
volue=0x00;
}
return 0;
}
void Data_Processing(void)//用于clk数据的写入 250us延时表示间隔 350us的clk拉高表示写入1 100us的clk拉高表示写入0
{
if(tap==0x01){
SYSTICK_ClearSystickVal();
while(SYSTICK_GetVal()>LF_350us);
CLK(0);
}else{
SYSTICK_ClearSystickVal();
while(SYSTICK_GetVal()>LF_100us);
CLK(0);
}
SYSTICK_ClearSystickVal();
while(SYSTICK_GetVal()>LF_250us);//拉低250us表示间隔
CLK(1);//再重新拉高用于写入
}
void write_od(uint8_t voled)//1P*与00的写入(即写入与读取的前两位)
{
SYSTICK_ClearSystickVal();
while(SYSTICK_GetVal()>LF_Star);
CLK(0);//
SYSTICK_ClearSystickVal();
while(SYSTICK_GetVal()>LF_350us);
CLK(1);
tap=voled;
tap&=0x10;
if(tap==0x10){ //两个data_processing ,写入两位
tap=0x01;
Data_Processing();//
}else{
tap=0x00;
Data_Processing();//
}
tap=voled;
tap&=0x01;
Data_Processing();//
}
void write_lock(uint8_t voled)//写入锁定位
{
tap=voled;
tap&=0x01;
Data_Processing();
}
void write_data() //写入4bit数据 即32位
{
uint8_t i,j,voled_1;
for(j=0;j<4;j++)
{
voled_1=data_tap[j];
for(i=0;i<8;i++)
{
tap=voled_1;
tap&=0x01;
Data_Processing();//
voled_1>>=1;
}
}
}
void write_add(uint8_t voled) //写入页的块地址
{
tap=voled;
tap&=0x04;
if(tap==0x04) //三个data_processing ,写入三位
{
tap=0x01;
Data_Processing();//
}
else
{
tap=0x00;
Data_Processing();//
}
tap=voled;
tap&=0x02;
if(tap==0x02)
{
tap=0x01;
Data_Processing();//
}
else
{
tap=0x00;
Data_Processing();//
}
tap=voled;
tap&=0x01;
Data_Processing();//
}
int8_t LF125K_read_1_page(uint8_t* buf) //读取第一页,正常读,直接读的第1页第1块的内容,即自带的id
{
uint8_t buf1[8];
memset(buf, 0, sizeof(buf1));
write_od(0x11);
SYSTICK_Delay10ms(1);
if(REM_Processing(buf))
return 1;
SYSTICK_Delay10ms(5);
write_od(0x11);//读取两次防止出错
SYSTICK_Delay10ms(1);
if(REM_Processing(buf1))
return 1;
if (memcmp(buf1,buf,8) != 0){
return 1;
}
return 0;
}
uint8_t jj=0;
void LF125K_demo(void)
{
int ret;
uint8_t buf[8];
//uint8_t pwd[4]={0x80,0x82,0x0,0x0};//写密码是用的,设置的密码
memset(buf, 0, sizeof(buf));
printf("低频卡测试\r\n");
ret=LF125K_read_1_page(buf);//读取第一页第1块的内容
//ret=LF125K_read_0_page_protect(0x01,buf,pwd);//用密码读取第0页第6块的内容
//ret=LF125K_read_0_page(0x06,buf);//0x06表示块的地址,可以更改
if(ret == 0)
{
printf("低频卡获取成功!");
for(jj=0;jj<1;jj++){
printf("id card:%X %X %X %X %X %X %X %X\r\n", buf[0+jj*8], buf[1+jj*8], buf[2+jj*8], buf[3+jj*8], buf[4+jj*8], buf[5+jj*8], buf[6+jj*8], buf[7+jj*8]);
}
}
else
{
printf("低频卡获取失败!");
}
}
int8_t LF125K_read_0_page(uint8_t adr,uint8_t* buf) //无密码的读
{
uint8_t buf1[8];
adr &= 0x7;
write_od(0x10);
write_lock(0x00);
write_add(adr);
SYSTICK_Delay10ms(2);
REM_Processing(buf1);
SYSTICK_Delay10ms(2);
write_od(0x10);
write_lock(0x00);
write_add(adr);
SYSTICK_Delay10ms(2);
REM_Processing(buf);
if(memcmp(buf1,buf,8)!=0)
return M_OK+1;
return M_OK;
}
int8_t LF125K_write_0_page(unsigned char adr,unsigned char *buf) //无密码的写
{
uint8_t buf1[10];
uint8_t lock=0;
if((adr&0x80) == 0x80)//防止超出块大小
lock = 1;
adr &=0x07;
if(adr==0x00)//块0 配置区 防止误操作
return M_OK+1;
write_od(0x10);
write_lock(lock);//写1固化
data_tap[0]=buf[0];
data_tap[1]=buf[1];
data_tap[2]=buf[2];
data_tap[3]=buf[3];
write_data();
write_add(adr);
SYSTICK_Delay10ms(2);
write_od(0x10);
write_lock(0x00);
write_add(adr);
SYSTICK_Delay10ms(2);
REM_Processing(buf1);
if(memcmp(buf1,buf,4)!=0) //重新读出,防止写入错误
return M_OK+1;
return M_OK;
}
/*
*@brief 带密码写块数据.
*@param .
*@retval .
*/
void LF125K_write_0_page_protect(uint8_t adr,uint8_t *buf,uint8_t *pwd)
{
uint8_t lock=0;
if ((adr&0x80) == 0x80) {
lock = 1;
}
write_od(0x10);
data_tap[0]=pwd[0];
data_tap[1]=pwd[1];
data_tap[2]=pwd[2];
data_tap[3]=pwd[3];
write_data();//
write_lock(lock);
data_tap[0]=buf[0];
data_tap[1]=buf[1];
data_tap[2]=buf[2];
data_tap[3]=buf[3];
write_data();
write_add(adr);
SYSTICK_Delay10ms(1);
}
/*
*@brief 带密码读块数据.
*@param .
*@retval .
*/
int8_t LF125K_read_0_page_protect(uint8_t adr,uint8_t *buf,uint8_t *pwd)
{
write_od(0x10);
data_tap[0]=pwd[0];
data_tap[1]=pwd[1];
data_tap[2]=pwd[2];
data_tap[3]=pwd[3];
write_data();
write_lock(0x00);
write_add(adr);
SYSTICK_Delay10ms(1);
if(REM_Processing(buf))
return 1;
return 0;
}
/*
*@brief 无密码初始化,初始一次就行了
*@param .
*@retval 0:success
1:false.
*/
void LF125K_card_init(void)//对第0页的块0内容进行设置,可是你去比较这值你会发现很多对不上的
{
write_od(0x10);
write_lock(0x00);
data_tap[0]=0x00;
data_tap[1]=0x28;//0x28;
data_tap[2]=0x01;
data_tap[3]=0x17;
write_data();
write_add(0x00);
}
/*
*@brief 加密卡片.
*@param .
*@retval .
*/
void LF125K_set_password (void)//对第0页的块0内容进行设置,可是你去比较这值你会发现很多对不上的
{
write_od(0x10);
write_lock(0x00);
data_tap[0]=0x00;
data_tap[1]=0x28;
data_tap[2]=0x41;
data_tap[3]=0x1f;
write_data();
write_add(0x00);
}
/*
*@brief 清除卡片密码.
*@param .
*@retval .
*/
int8_t LF125K_clear_pwd (uint8_t *pwd)
{
uint8_t buf[10];
write_od(0x10);
data_tap[0]=pwd[0];
data_tap[1]=pwd[1];
data_tap[2]=pwd[2];
data_tap[3]=pwd[3];
write_data();
write_lock(0x00);
data_tap[0]=0x00;
data_tap[1]=0x28;
data_tap[2]=0x01;
data_tap[3]=0x17;
write_data();
write_add(0);
SYSTICK_Delay10ms(1);
if(REM_Processing(buf))
return 1;
return 0;
}
lf15k.h
#ifndef __LF125K_H
#define __LF125K_H
/* Includes --------------------*/
#include "stm32f10x.h"
/* Types -----------------------*/
/* Constants -------------------*/
/* Define ----------------------*/
/* Variables -------------------*/
/* Functions prototypes --------*/
extern void LF125K_init(void);
extern void LF125K_demo(void);
void LF125K_set_password (void);
//adr(0~7), buf(return 4 bytes)
extern int8_t LF125K_read_0_page(uint8_t adr,uint8_t *buf);
//adr(0~7), buf(4 bytes)
extern int8_t LF125K_write_0_page(uint8_t adr,uint8_t *buf);
//return 8 bytes
extern int8_t LF125K_read_1_page(uint8_t *buf);
extern void LF125K_card_init(void);
extern int8_t LF125K_set_pwd (uint8_t *pwd);
extern int8_t LF125K_clear_pwd (uint8_t *pwd);
extern void LF125K_write_0_page_protect(uint8_t adr,uint8_t *buf,uint8_t *pwd);
extern int8_t LF125K_read_0_page_protect(uint8_t adr,uint8_t *buf,uint8_t *pwd);
#endif
systick.c
/*************************************************************************
# FileName: bsp_systick.c
# Author: Allen
# Email: [email protected]
# HomePage: Allen
# Brief:
# LastChange: 2014-05-09 11:21:53
*************************************************************************/
/* Includes ------------------------------------------------------------*/
#include
#include "stm32f10x.h"
#include "systick.h"
/* Types ---------------------------------------------------------------*/
/* Constants -----------------------------------------------------------*/
/* Define --------------------------------------------------------------*/
/* Variables -----------------------------------------------------------*/
volatile long jiffies=0;
/* Functions prototypes ------------------------------------------------*/
/* Functions -----------------------------------------------------------*/
/*
@brief systick.
@param None.
@retval None.
*/
//#include "debug_printf.h"
void SYSTICK_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = (uint8_t)SysTick_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void SYSTICK_Configuration (void)
{
jiffies = 0;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
if (720000 > SysTick_LOAD_RELOAD_Msk) while(1);/* Reload value impossible */
SysTick->LOAD = (720000 & SysTick_LOAD_RELOAD_Msk) - 1;/* set reload register */
//NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);/* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL = 0;/* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;/* Enable SysTick IRQ and SysTick Timer */
// if(SysTick_Config(720000) == 1){//10ms
// printf("\r\nsystick fail");
// while(1);
// }
}
void SYSTICK_init(void)
{
//systick NVIC init
SYSTICK_NVIC_Configuration();
//systick init
SYSTICK_Configuration();
}
void SYSTICK_IntDisable(void)
{
SysTick->CTRL &=(~SysTick_CTRL_TICKINT_Msk);
}
void SYSTICK_IntEnable(void)
{
SysTick->CTRL |=(SysTick_CTRL_TICKINT_Msk);
}
void SYSTICK_ClearSystickVal (void)
{
SysTick->VAL = 0;
}
long SYSTICK_GetVal(void)
{
return SysTick->VAL;
}
void SYSTICK_Delay10ms(long i)
{
long jif;
SysTick->VAL = 0;
jif = i+jiffies;
while(jif>jiffies);
}
long SYSTICK_get_time(void)
{
return jiffies;
}
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
//10ms one time
if(++jiffies>3000000)
jiffies=0;
}
/*********************************END OF FILE****************************/
systick.h
*************************************************************************/
/* Define to prevent recursive inclusion -------------------------------*/
#ifndef SYSTICK_H
#define SYSTICK_H
/* Includes ------------------------------------------------------------*/
/* Exported types ------------------------------------------------------*/
/* Exported constants --------------------------------------------------*/
/* Exported define -----------------------------------------------------*/
/* Exported variables --------------------------------------------------*/
extern volatile long jiffies;
/* Exported functions prototypes ---------------------------------------*/
void SYSTICK_init(void);
extern void SYSTICK_Configuration (void);
extern void SYSTICK_Delay10ms(long i);
extern void SYSTICK_ClearSystickVal (void);
extern long SYSTICK_GetVal(void);
extern long SYSTICK_get_time(void);
//extern void delay_ms(int ms);
//extern void delay_us(int us);
#endif
/*********************************END OF FILE****************************/
main.c
若果你只读第1页的内容,你就不需要改了,如果你要都第0页的内容, //LF125K_card_init();//初始化值需要一次,一次后它会自动保存 把这个函数注释取消,主要这个只要一次就行,但你放着也没事,还有就是void LF125K_demo(void)函数中把读第1页的给注释掉,第0页的读取注释取消。带密码读的,就将main和void LF125K_demo(void)函数中的pwd数组注释取消,同时需要密码初始化一次,都数据选择密码读取,先消除密码读取也就只要消除一次就行,读取函数改下就行。需要特别注意的是,你用密码读前先将第0页第7块的内容读取下,否则它是与第0页第7块内容进行比较的,你读取和清楚密码都是需要密码的,你若不小心忘记了密码,那就啥都干不了了。你想改密码也是直接修改第0页第7块前32位就行了。
#include "stm32f10x.h"
#include "lf125k.h"
#include "delay.h"
#include "systick.h"
#include "usart1.h"
int main(void)
{
//uint8_t pwd[8]={0x80,0x82,0x0,0,0,0,0,0};//设置密码用的
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级
uart_init(115200);
delay_init();
SYSTICK_init();
LF125K_init();
//LF125K_set_password();
//LF125K_card_init();//初始化值需要一次,一次后它会自动保存
//LF125K_clear_pwd (pwd);//设置密码后进行密码的清除
while(1)
{
LF125K_demo();
delay_ms(1000);
}
}
Delay.c
/******************************************************************************
* @ File name --> delay.c
* @ Author --> By@ Sam Chan
* @ Version --> V1.0
* @ Date --> 10 - 20 - 2012
* @ Brief --> 系统延时相关的函数
*
* @ 详细说明请参考《Cortex-M3权威指南(中文)》第133 ~ 134页 第8章 SysTick定时器介绍
*
* @ Copyright (C) 20**
* @ All rights reserved
*******************************************************************************
*
* File Update
* @ Version --> V1.0.1
* @ Author --> By@ Sam Chan
* @ Date --> 02 - 26 - 2014
* @ Revise --> 增加另外一种延时计算方法
*
* @ Version --> V1.0.2
* @ Author --> By@ Sam Chan
* @ Date --> 05 - 10 - 2014
* @ Revise --> 增加对C++环境支持
*
* @ Version --> V1.1
* @ Author --> By@ Sam Chan
* @ Date --> 05 - 24 - 2014
* @ Revise --> 修改在跑ucos时初始化嘀嗒定时器、延时us和ms函数
*
******************************************************************************/
/******************************************************************************
* @ SysTick定时器 相关控制寄存器说明
@ 1、SysTick控制及状态寄存器(地址:0xE000_E010)复位值为0
bit16 COUNTFLAG(R) -> 如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1。如果读取该位,该位将自动清零
bit2 CLKSOURCE(R/W) -> 0=外部时钟源(STCLK)。1=内核时钟(FCLK)
bit1 TICKINT(R/W) -> 1=SysTick倒数到0时产生SysTick异常请求,0=数到0时无动作
bit0 ENABLE(R/W) -> SysTick定时器的使能位
@ 2、SysTick重装载数值寄存器(地址:0xE000_E014)复位值为0
[23:0] RELOAD(R/W) -> 当倒数至零时,将被重装载的值
@ 3、SysTick当前数值寄存器(地址:0xE000_E018) 复位值为0
[23:0] CURRENT(R/Wc) -> 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG标志
@ 4、SysTick校准数值寄存器(地址:0xE000_E01C)复位值: bit31未知。bit30未知。[23:0]为0
bit32 NOREF(R) -> 1=没有外部参考时钟(STCLK不可用)。0=外部参考时钟可用
bit30 SKEW(R) -> 1=校准值不是准确的10ms。0=校准值是准确的10ms
[23:0] TENMS(R/W) -> 10ms的时间内倒计数的格数。芯片设计者应该通过Cortex‐M3的输入信号提供该数值。若该值读回零,则表示无法使用校准功能
******************************************************************************/
#include "delay.h"
/******************************************************************************
使用嵌入式操作系统时初始化心跳函数等
******************************************************************************/
#if _SYSTEM_SUPPORT_ROTS //定义了则支持实时嵌入式操作系统
#include "includes.h" //增加操作系统需要头文件
/******************************************************************************
* Function Name --> SysTick定时器心跳初始化
* Description --> 主要是初始化SysTick寄存器
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void OS_Heart_Init(void)
{
delay_init();
}
/******************************************************************************
* Function Name --> SysTick定时器中断服务函数
* Description --> 在此编写了,则stm32f10x_it.c中就不需要编写,否则stm32f10x_it.c中就要编写
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void SysTick_Handler(void)
{
/* 编写与SysTick定时器中断操作相关的API函数调用 */
OSIntEnter(); //ucos进入中断
OSTimeTick(); //调用ucos的时钟服务函数
OSIntExit(); //ucos退出中断
}
#endif /* end _SYSTEM_SUPPORT_ROTS */
/******************************************************************************
结束嵌入式操作系统心跳设置
******************************************************************************/
//=========================================================
#if _USER_SysTick==1 //定义了则使用SysTick定时器做延时函数计数
//=========================================================
/******************************************************************************
定义计算变量
******************************************************************************/
static uint8_t fac_us=0; //us延时倍乘数
static uint16_t fac_ms=0; //ms延时倍乘数
/******************************************************************************
* Function Name --> 初始化延时函数
* Description --> 主要是初始化SysTick寄存器
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void delay_init(void)
{
#if _SYSTEM_SUPPORT_ROTS //运行在ucos上
uint32_t RELOAD=0; //当计数器倒数到0时的重装值,有效位:0 ~ 23
#endif
/* 根据SysTick定时器的时钟分频来确定重装值 */
/* 8分频时除以8000‘000,1分频时除以1000’000 */
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK / 8
fac_us = SystemCoreClock / 8000000; //系统时钟的 1/8
#if _SYSTEM_SUPPORT_ROTS //运行在ucos上
RELOAD = SystemCoreClock / 8000000; //每秒钟的计数次数,单位Hz
RELOAD *= 1000000 / OS_TICKS_PER_SEC; //根据操作系统的心跳时长来计算溢出时间,单位:KHz
//RELOAD为24位计数器,最大值为:16777216
fac_ms = 1000 / OS_TICKS_PER_SEC;
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //开启SysTick定时器中断请求
SysTick->LOAD = RELOAD; //溢出计数值,每1/TICKINT_CNT秒中断一次
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
#else
fac_ms = (uint16_t)fac_us*1000; //ms需要的SysTick时钟数
#endif /* end _SYSTEM_SUPPORT_ROTS */
}
/******************************************************************************
* Function Name --> 延时n个us
* Description --> none
* Input --> nus:要延时的us数
* Output --> none
* Reaturn --> none
******************************************************************************/
void delay_us(uint32_t nus)
{
uint32_t temp=0;
#if _SYSTEM_SUPPORT_ROTS //运行在ucos上
uint32_t VAL_Prev=0; //开始计时之前的值
uint32_t VAL_Now=0; //当前计时值
uint32_t VAL_cnt=0; //计数
uint32_t Reload=SysTick->LOAD; //获取到LOAD的值
temp = nus*fac_us; //得到延时的节拍数
VAL_Prev = SysTick->VAL; //保存当前的计数值
while(1)
{
VAL_Now = SysTick->VAL; //读取数值
if(VAL_Now != VAL_Prev)
{
if(VAL_Now < VAL_Prev) VAL_cnt += VAL_Prev-VAL_Now; //因为SysTick是一个递减的定时器
else VAL_cnt += Reload - VAL_Now + VAL_Prev;
VAL_Prev = VAL_Now; //刷新
if(VAL_cnt >= temp) break; //超过/等于需要的延时值了,则退出循环
}
};
#else
SysTick->LOAD = nus*fac_us; //时间加载
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
do
{
temp = SysTick->CTRL;
}while(temp&0x01&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL = 0x00; //清空计数器
#endif /* end _SYSTEM_SUPPORT_ROTS */
}
/******************************************************************************
* Function Name --> 延时n个ms
* Description --> SysTick->LOAD为24位寄存器,所以,最大延时为:
* nms <= 0xffffff*8*1000/SYSCLK
* SYSCLK单位为Hz,nms单位为ms
* 注意nms的范围 0 ~ 1864(72M情况下)
* Input --> nms:要延时的ms数
* Output --> none
* Reaturn --> none
******************************************************************************/
void delay_ms(uint16_t nms)
{
#if _SYSTEM_SUPPORT_ROTS //使用ucos了
if(OSRunning == 1) //ucos已经在跑了
{
if(nms > fac_ms) //延时大于ucos基数
{
OSTimeDly(nms/fac_ms); //采用ucos延时
}
nms %= fac_ms; //ucos无法提供小于节拍的延时了
}
delay_us((uint32_t)(nms*1000)); //采用普通的延时
#else
uint32_t temp;
SysTick->LOAD = (uint32_t)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
do
{
temp = SysTick->CTRL;
}while(temp&0x01&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL = 0x00; //清空计数器
#endif /* end _SYSTEM_SUPPORT_ROTS */
}
//=========================================================
#else //使用另外资源进行延时计数
//=========================================================
/******************************************************************************
* Function Name --> 初始化延时函数
* Description --> 主要Cortex-M3内核对系统时钟计数单元
* 详细见《Cortex-M3权威指南(中文)》第216页 a) 时钟周期(CYCCNT) 的内容
* 周立功《CM3计数参考手册》第28、29页、第110、125页
* Input --> SYSCLK:系统工作最高的频率。单位MHz
* Output --> none
* Reaturn --> none
******************************************************************************/
void delay_init(void)
{
DEM_CTRL |= 1<<24; //该位必须为1,使能跟踪和调试模块的使用。详细见:周立功《CM3计数参考手册》第115页介绍
//在没有使用跟踪时,该位使能对功率使用的控制。它能够由应用程序或调试器使能,供ITM使用
//在DWT能够使用之前,调试异常和监控控制寄存器的TRCENA(bit24)位必须置位
DWT_CTRL |= 1<<0; //使能DWT_CYCCNT计数器。
//如果不使能,则计数器不执行计数操作,因此不会产生PC采样或CYCCNTENA事件。
//在正常使用时,CYCCNT计数器应由调试器初始化为0。
}
/******************************************************************************
* Function Name --> 延时n个us
* Description --> none
* Input --> nus:要延时的us数
* Output --> none
* Reaturn --> none
******************************************************************************/
void delay_us(uint32_t nus)
{
uint32_t savecount,endcnt,CPU_cnt;
savecount = DWT_CYCCNT; //保存计数器当前数值
CPU_cnt = nus*(SystemCoreClock/(1000*1000)); //计算达到所需延时值的CPU时钟数。即多少个系统时钟计数
//得到更精确延时时间,减去前面代码运行的时间即可
endcnt = savecount + CPU_cnt; //计算所需延时时间DWT_CYCCNT的计数值,在溢出时返回到0
if(endcnt > savecount) //所需延时值大于当前计数值
{
while(DWT_CYCCNT < endcnt); //循环等待所需要的延时时间的CPU时钟计数值
}
else //小于当前计数值
{
while(DWT_CYCCNT > endcnt); //等待计数器溢出翻转
while(DWT_CYCCNT < endcnt); //等待所需延时时间到达
}
}
void sdelay(uint32_t s)
{
uint8_t i;
while(s--)
{
i=1;
while(i--);
}
}
//=========================================================
#endif
//=========================================================
delay.h
/******************************************************************************
* @ File name --> delay.h
* @ Author --> By@ Sam Chan
* @ Version --> V1.0
* @ Date --> 10 - 20 - 2012
* @ Brief --> 系统延时相关的函数
*
* @ 详细说明请参考《Cortex-M3权威指南(中文)》第133 ~ 134页 第8章 SysTick定时器介绍
*
* @ Copyright (C) 20**
* @ All rights reserved
*******************************************************************************
*
* File Update
* @ Version --> V1.0.1
* @ Author --> By@ Sam Chan
* @ Date --> 02 - 26 - 2014
* @ Revise --> 增加另外一种延时计算方法
*
* @ Version --> V1.0.2
* @ Author --> By@ Sam Chan
* @ Date --> 05 - 10 - 2014
* @ Revise --> 增加对C++环境支持
*
* @ Version --> V1.1
* @ Author --> By@ Sam Chan
* @ Date --> 05 - 24 - 2014
* @ Revise --> 修改在跑ucos时初始化嘀嗒定时器、延时us和ms函数
*
******************************************************************************/
#ifndef _delay_h_
#define _delay_h_
/*===========================================================================*/
#ifdef __cplusplus /* C++支持 */
extern "C"{
#endif
/*===========================================================================*/
/******************************************************************************
外部函数头文件
******************************************************************************/
#include "sys.h"
/******************************************************************************
延时函数计数来源定义
******************************************************************************/
#if _SYSTEM_SUPPORT_ROTS==1 //运行在ucos上
#define _USER_SysTick 1 //1:使用SysTick定时器做延时函数计数
#else
#define _USER_SysTick 0 /* 定义是否使用SysTick定时器做延时计数函数 */
//0:使用其他方式
//1:使用SysTick定时器做延时函数计数
#endif
/******************************************************************************
定义其他延时计数资源
******************************************************************************/
#if !_USER_SysTick //使用其他方式做延时函数计数
#define DWT_CTRL *(volatile uint32_t*)0xe0001000 //DWT控制寄存器
#define DWT_CYCCNT *(volatile uint32_t*)0xe0001004 //DWT当前PC采样周期计数寄存器
//详细见:周立功《CM3计数参考手册》第129页介绍
#define DWT_CPICNT *(volatile uint32_t*)0xe0001008 //DWT当前CPI计数寄存器
#define DEM_CTRL *(volatile uint32_t*)0xe000edfc //调试异常和监控控制寄存器
#endif
/******************************************************************************
外部功能函数
******************************************************************************/
#if _USER_SysTick==1 //定义了则使用SysTick定时器做延时函数计数
void delay_init(void); //初始化延时函数
void delay_us(uint32_t nus); //延时n个us
void delay_ms(uint16_t nms); //延时n个ms
#else //否则使用其他方式
void delay_init(void);//void delay_init(uint8_t SYSCLK); //初始化延时函数
void delay_us(uint32_t nus); //延时n个us
//延时ms级定义,延时范围:1 ~ 65535ms。延时最大值可变,不爆机uint32_t/1000范围即可
#define delay_ms(nms) delay_us((uint16_t)nms*1000)
#endif //end _USER_SysTick
#if _SYSTEM_SUPPORT_ROTS==1 //定义了则支持实时嵌入式操作系统
void OS_Heart_Init(void); //SysTick定时器心跳初始化
#endif
void sdelay(uint32_t s);
/*===========================================================================*/
#ifdef __cplusplus /* C++支持 */
}
#endif
/*===========================================================================*/
#endif /* end delay.h */