电赛2019年F题纸张测量FDC2214的初始化代码(含STM32f103zet6和f103c8t6)胎教式

(一)我的感受

其实第一次接触这一个题目的时候,觉得还是不难的,(因为相对于我实验室的同学做的其他的一些控制类题目)。我觉得在代码方面完成题目要求的不难,就是在机械结构方面要做好,我做的装置机械机构不算是很好,就是两块极板压下去不是完全对准的,比较容易产生误差,而且压下去的东西还是一个大电机。下面附图。

进入主题啦!!!ヾ(^ ▽ ^*)))

FDC2214的使用

电容式传感是一种低功耗、低成本且高分辨率的非接触式感测技术, 适用于从接近检测、手势识别到远程液位感测的各项应用。电容式传感系统中的传感器可以采用任意金属或导体,因此可实现高度灵活的低成本系统设计。

FDC2214寄存器的地址

在这里插入图片描述
我觉得这个寄存器部分是最重要的部分。(我在写代码时经常在这里犯病)
还有就是FDC2214是用IIC通信的,你可以直接使用正点原子的例程可以的。

FDC写操作

```c
void FDC_write_reg(u8 addr,u16 value)   //addr 为寄存器地址,value为需要写入的寄存器数据 
{ 
	   IIC_Start();                    //产生START信号
	   IIC_Send_Byte(FDC_Address_W);   //发送从机地址和写信号
	   IIC_Wait_Ack();                 //等待ACK
	   IIC_Send_Byte(addr);            //发送需要写入的寄存器地址
	   IIC_Wait_Ack();                 //等待ACK
	   IIC_Send_Byte(value>>8);        //发送高8位数据
	   IIC_Wait_Ack();                 //等待ACK
	   IIC_Send_Byte(value&0xFF);      //发送低8位数据
	   IIC_Wait_Ack();                 //等待ACK
       IIC_Stop();                      //产生STOP信号
	   delay_ms(1);
}
FDC读操作
u16 FDC_read_reg(u8 addr)
{
		 IIC_Start();                    //产生START信号
	     IIC_Send_Byte(FDC_Address_W);   //发送写命令
	     IIC_Wait_Ack();		
	     IIC_Send_Byte(addr);            //发送需要读的寄存器的地址
		 IIC_Wait_Ack();
	
	     IIC_Start();
	     IIC_Send_Byte(FDC_Address_R);  //发送读命令
	     IIC_Wait_Ack();
	     
	     Receive_Date[0]=IIC_Read_Byte(1);  //读高8位
		 Receive_Date[1]=IIC_Read_Byte(0);  //读低8位
	     IIC_Stop();	                    //产生STOP信号
	     C_Data=(Receive_Date[0]<<8)+ Receive_Date[1];
		 return C_Data;
}
FDC2214读高八位和第八位的操作
u8 FDC_read_reg_high(u8 addr)
{
		 IIC_Start();
	     IIC_Send_Byte(FDC_Address_W);   
	     IIC_Wait_Ack();		
	     IIC_Send_Byte(addr);
		 IIC_Wait_Ack();
	
	     IIC_Start();
	     IIC_Send_Byte(FDC_Address_R);  
	     IIC_Wait_Ack();
	     
		 Receive_Date[0]=IIC_Read_Byte(1);
		 Receive_Date[1]=IIC_Read_Byte(0);
	     IIC_Stop();	
		 return Receive_Date[0];
}



u8 FDC_read_reg_low(u8 addr)
{
		   IIC_Start();
	     IIC_Send_Byte(FDC_Address_W);   
	     IIC_Wait_Ack();		
	     IIC_Send_Byte(addr);
			 IIC_Wait_Ack();
	
	     IIC_Start();
	     IIC_Send_Byte(FDC_Address_R);  
	     IIC_Wait_Ack();
	     
			 Receive_Date[0]=IIC_Read_Byte(1);
			 Receive_Date[1]=IIC_Read_Byte(0);
	     IIC_Stop();	
			 return Receive_Date[1];
}
FDC2214设置寄存器
void FDC_Start(void)  
{    
FDC_write_reg(0x08,0x8329);   //(CHx_RCOUNT*16)/55M ==9.76ms,,每10ms左右可以读一次值
	FDC_write_reg(0x09,0x8329);
    FDC_write_reg(0x0A,0x8329);	
	FDC_write_reg(0x0B,0x8329);
	
	FDC_write_reg(0x10,0x000A);  //设置4个通道最小稳定时间
	FDC_write_reg(0x11,0x000A);
	FDC_write_reg(0x12,0x000A);
	FDC_write_reg(0x13,0x000A);
	
    FDC_write_reg(0x14,0x1001); //时钟除以1,设置传感器频率在0.01M到8.5M之间
	FDC_write_reg(0x15,0x1001);
	FDC_write_reg(0x16,0x1001);
	FDC_write_reg(0x17,0x1001);
	
	FDC_write_reg(0x19,0x0000); //不设置中断标志位
	FDC_write_reg(0x1B,0xC20D);//使能0,1,2,3通道,且带宽设置为10M
 
	FDC_write_reg(0x1E,0x8000); //设置4个通道的驱动电流
    FDC_write_reg(0x1F,0x8000);
	FDC_write_reg(0x20,0x8000);
	FDC_write_reg(0x21,0x8000);
 
 	
	FDC_write_reg(0x1A,0x1401);	//使能FDC2214,且取内部时钟为参考时钟
}
还有源文件包括的变量
int FDC_Address_W =0x54;
int FDC_Address_R =0x55;
int Receive_Date[10000] ;//为接收数据的数组;
u16 C_Data; //为一个16位无符号的整型
头文件
#ifndef __FDC2214_H
#define __FDC2214_H
#include <sys.h>
//IO口方向
 
#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
 
//IO操作函数	 
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA	 
#define READ_SDA   PBin(7)  //SDA输入
 
//IIC函数
void IIC_Init(void);                			 
void IIC_Start(void);				
void IIC_Stop(void);	  			
void IIC_Send_Byte(u8 txd);			
u8 IIC_Read_Byte(unsigned char ack);
u8 IIC_Wait_Ack(void); 				
void IIC_Ack(void);					
void IIC_NAck(void);				
 
void FDC_write_reg(u8 addr,u16 value);  
void FDC_Start(void);
u16 FDC_read_reg(u8 addr);
u8 FDC_read_reg_high(u8 addr);
u8 FDC_read_reg_low(u8 addr);
 
#endif




这是我用的初始化,你还想更理解FDC2214,看一下这个文章,fdc2214使用注意事项

还有就是上面是我在精英板用的初始化,下面还有一种对FDC2214的初始化,如果上面的初始化不能用的话就直接用下面的初始化(大同小异,只是一些地方的读写地址是分开两部分)。
void FDC_IIC_Delay(void)
{
    delay_us(2);
}
void FDC_IIC_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//先使能外设IO PORTC时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
    //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //IO口速度为50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure);                        //根据设定参数初始化GPIO

  GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);                  //PC.4,PC.5 输出高
}

//产生IIC起始信号
void FDC_IIC_Start(void)
{
    FDC_SDA_OUT();     //sda线输出
    FDC_IIC_SDA=1;
    FDC_IIC_SCL=1;
    FDC_IIC_Delay();
     FDC_IIC_SDA=0;//START:when CLK is high,DATA change form high to low
    FDC_IIC_Delay();
    FDC_IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void FDC_IIC_Stop(void)
{
    FDC_SDA_OUT();//sda线输出
    FDC_IIC_SCL=0;
    FDC_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     FDC_IIC_Delay();
    FDC_IIC_SCL=1;
    FDC_IIC_SDA=1;//发送I2C总线结束信号
    FDC_IIC_Delay();
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 FDC_IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    FDC_SDA_IN();      //SDA设置为输入
    FDC_IIC_SDA=1;FDC_IIC_Delay();
    FDC_IIC_SCL=1;FDC_IIC_Delay();
    while(FDC_READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            FDC_IIC_Stop();
            return 1;
        }
    }
    FDC_IIC_SCL=0;//时钟输出0
    return 0;
}


//产生ACK应答
//void FDC_IIC_Ack(void)
//{
//    FDC_IIC_SCL=0;
//    FDC_SDA_OUT();
//    FDC_IIC_SDA=0;
//    FDC_IIC_Delay();
//    FDC_IIC_SCL=1;
//    FDC_IIC_Delay();
//    FDC_IIC_SCL=0;
//}

//debug
void FDC_IIC_Ack(void)
{
    FDC_IIC_SCL=0;
    FDC_IIC_SDA=0;
    FDC_IIC_Delay();
    FDC_IIC_SCL=1;
    FDC_IIC_Delay();
    FDC_IIC_SCL=0;
    FDC_IIC_Delay();
    FDC_IIC_SDA=1;
}


//不产生ACK应答
void FDC_IIC_NAck(void)
{
    FDC_IIC_SCL=0;
    FDC_SDA_OUT();
    FDC_IIC_SDA=1;
    FDC_IIC_Delay();
    FDC_IIC_SCL=1;
    FDC_IIC_Delay();
    FDC_IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void FDC_IIC_Send_Byte(u8 txd)
{
  u8 t;
    FDC_SDA_OUT();
    FDC_IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        FDC_IIC_SDA=(txd&0x80)>>7;
        txd<<=1;
            FDC_IIC_SCL=1;
            FDC_IIC_Delay();
            FDC_IIC_SCL=0;
            FDC_IIC_Delay();
    }
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 FDC_IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    FDC_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        FDC_IIC_SCL=0;
        FDC_IIC_Delay();
        FDC_IIC_SCL=1;
        receive<<=1;
        if(FDC_READ_SDA)receive++;
        FDC_IIC_Delay();
    }
    if (!ack)
        FDC_IIC_NAck();//发送nACK
    else
        FDC_IIC_Ack(); //发送ACK
    return receive;
}

u8 Set_FDC2214(u8 reg,u8 MSB,u8 LSB)
{
    FDC_IIC_Start();
    FDC_IIC_Send_Byte((FDC2214_ADDR<<1)|0);//发送器件地址+写命令
    if(FDC_IIC_Wait_Ack())    //等待应答
    {
        FDC_IIC_Stop();
        return 1;
    }
    FDC_IIC_Send_Byte(reg);//写寄存器地址
    FDC_IIC_Wait_Ack();         //等待应答
    FDC_IIC_Send_Byte(MSB);  //发送数据1
    if(FDC_IIC_Wait_Ack())     //等待ACK
    {
        FDC_IIC_Stop();
        return 1;
    }
    FDC_IIC_Send_Byte(LSB);  //发送数据2
    if(FDC_IIC_Wait_Ack())     //等待ACK
    {
        FDC_IIC_Stop();
        return 1;
    }
    FDC_IIC_Stop();
    return 0;
}

u16 FDC_Read(u8 reg)
{
    u16 res;
   FDC_IIC_Start();
    FDC_IIC_Send_Byte((FDC2214_ADDR<<1)|0);//发送器件地址+写命令
    FDC_IIC_Wait_Ack();        //等待应答
    FDC_IIC_Send_Byte(reg);    //写寄存器地址
    FDC_IIC_Wait_Ack();        //等待应答
    FDC_IIC_Start();
    FDC_IIC_Send_Byte((FDC2214_ADDR<<1)|1);//发送器件地址+读命令
    FDC_IIC_Wait_Ack();        //等待应答
    res=FDC_IIC_Read_Byte(1)<<8;//读取数据,发送ACK

//    FDC_IIC_Ack();
    res|=FDC_IIC_Read_Byte(0);//读取数据,发送nACK
    FDC_IIC_Stop();            //产生一个停止条件
    return res;
}

u32 FCD2214_ReadCH(u8 index)//这个就是对不同通道的数据进行读取
{
    u32 result;
    switch(index)
    {
        case 0:
          result = FDC_Read(DATA_CH0)&0x0FFF;
          result = (result<<16)|(FDC_Read(DATA_LSB_CH0));//读取相对应通道的数值·
            break;
        case 1:
            result = FDC_Read(DATA_CH1)&0x0FFF;
          result = (result<<16)|(FDC_Read(DATA_LSB_CH1));
            break;
        case 2:
            result = FDC_Read(DATA_CH2)&0x0FFF;
          result = (result<<16)|(FDC_Read(DATA_LSB_CH2));
            break;
        case 3:
            result = FDC_Read(DATA_CH3)&0x0FFF;
          result = (result<<16)|(FDC_Read(DATA_LSB_CH3));
            break;
        default:break;
    }
    result =result&0x0FFFFFFF;//十六进制的数据转化成十进制的
    return result;
}

/*FDC2214初始化函数
 *返回值:0:初始化正常
 *       1:不正常
 */

float FDC2214_Init(void)
{
   
    FDC_GPIO_Init();
    FDC_IIC_Init();
        //设置Set_FDC2214寄存器
        Set_FDC2214(RCOUNT_CH0,0x34,0xFB);//参考计数转换间隔时间(T=(RCOUNT_CH0*16)/Frefx)
        Set_FDC2214(RCOUNT_CH1,0x34,0xFB);
        Set_FDC2214(RCOUNT_CH2,0x34,0xFB);
        Set_FDC2214(RCOUNT_CH3,0x34,0xFB);

        Set_FDC2214(SETTLECOUNT_CH0,0x00,0x1B);//转换之前的稳定时间(T=(SETTLECOUNT_CHx*16)/Frefx)
        Set_FDC2214(SETTLECOUNT_CH1,0x00,0x1B);
        Set_FDC2214(SETTLECOUNT_CH2,0x00,0x1B);
        Set_FDC2214(SETTLECOUNT_CH3,0x00,0x1B);

        Set_FDC2214(CLOCK_DIVIDERS_C_CH0,0x20,0x02);//选择在0.01MHz ~ 10MHz的传感器频率
        Set_FDC2214(CLOCK_DIVIDERS_C_CH1,0x20,0x02);//Frefx = Fclk = 43.4MHz/2(2分频)
        Set_FDC2214(CLOCK_DIVIDERS_C_CH2,0x20,0x02);//CHx_REF_DIVIDER=2;CHx_FIN_SEL=2
        Set_FDC2214(CLOCK_DIVIDERS_C_CH3,0x20,0x02);//CHx_REF_DIVIDER=2;CHx_FIN_SEL=2

        Set_FDC2214(DRIVE_CURRENT_CH0,0x78,0x00);//0.146ma(传感器时钟建立+转换时间的驱动电流)
        Set_FDC2214(DRIVE_CURRENT_CH1,0x78,0x00);
        Set_FDC2214(DRIVE_CURRENT_CH2,0x78,0x00);
        Set_FDC2214(DRIVE_CURRENT_CH3,0x78,0x00);

        Set_FDC2214(ERROR_CONFIG,0x00,0x00);//全部禁止错误汇报

        Set_FDC2214(MUX_CONFIG,0xC2,0x0D);//通道0,1,2 ,3;选择10Mhz为超过振荡槽振荡频率的最低设置,多通道,四通道

        Set_FDC2214(CONFIG,0x14,0x01);//激活模式,使用内部振荡器做参考频率,INTB引脚会随状态寄存器更新被置位
}
头文件
#ifndef __FDC2214_H
#define __FDC2214_H
#include "sys.h"

//IO方向设置
#define FDC_SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define FDC_SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

//IO操作函数
#define FDC_IIC_SCL    PBout(6)     //SCL
#define FDC_IIC_SDA    PBout(7)   //输出SDA
#define FDC_READ_SDA   PBin(7)         //输入SDA

/*FDC2214    iic从地址
 *ADDR = L , I2C Address = 0x2A
 *ADDR = H , I2C Address = 0x2B*/
#define FDC2214_ADDR 0x2A

/*FDC2214各个寄存器地址*/
#define DATA_CH0 0x00                     //数据寄存器
#define DATA_LSB_CH0 0x01
#define DATA_CH1 0x02
#define DATA_LSB_CH1 0x03
#define DATA_CH2 0x04
#define DATA_LSB_CH2 0x05
#define DATA_CH3 0x06
#define DATA_LSB_CH3 0x07
#define RCOUNT_CH0 0x08    //
#define RCOUNT_CH1 0x09
#define RCOUNT_CH2 0x0A
#define RCOUNT_CH3 0x0B
//#define OFFSET_CH0 0x0C  //FDC2114
//#define OFFSET_CH1 0x0D
//#define OFFSET_CH2 0x0E
//#define OFFSET_CH3 0x0F
#define SETTLECOUNT_CH0 0x10
#define SETTLECOUNT_CH1 0x11
#define SETTLECOUNT_CH2 0x12
#define SETTLECOUNT_CH3 0x13
#define CLOCK_DIVIDERS_C_CH0 0x14       //时钟分频
#define CLOCK_DIVIDERS_C_CH1 0x15
#define CLOCK_DIVIDERS_C_CH2 0x16
#define CLOCK_DIVIDERS_C_CH3 0x17
#define STATUS 0x18                     //状态寄存器
#define ERROR_CONFIG 0x19                 //错误报告设置
#define CONFIG 0x1A
#define MUX_CONFIG 0x1B
#define RESET_DEV 0x1C
#define DRIVE_CURRENT_CH0 0x1E          //电流驱动
#define DRIVE_CURRENT_CH1 0x1F
#define DRIVE_CURRENT_CH2 0x20
#define DRIVE_CURRENT_CH3 0x21
#define MANUFACTURER_ID 0x7E      //读取值:0x5449
#define DEVICE_ID 0x7F            //读取值:0x3055

//extern u16 Data_FDC;

//相关函数申明
u8 Set_FDC2214(u8 reg,u8 MSB,u8 LSB);

u16 FDC_Read(u8 reg);

//u16 FCD2214_ReadCH(u8 index);
u32 FCD2214_ReadCH(u8 index);
float FDC2214_Init(void);
void record(float Cap_final);
void Self_test(float Cap_final);
float Cap_Calculate(u8 chx);

#endif
还有就是在主函数里面读取相对应通道的数据
if(C_date==0x5449 && ID==0x3055)    //当为相应ID时才读取寄存器的值
				{				//读通道0数值	
		     C_CH0_data = FDC_read_reg(0x00)&0xFFF;
		     C_CH0_data_low = FDC_read_reg(0x01);
		     C_CHO_data_final =((C_CH0_data<<16)+C_CH0_data_low);
//读通道1数值		
		     delay_ms(50);
		     C_CH1_data = FDC_read_reg(0x02)&0xFFF;
		     C_CH1_data_low = FDC_read_reg(0x03);
		     C_CH1_data_final =((C_CH1_data<<16)+C_CH1_data_low);	
//读通道2数值
		     delay_ms(50);
		     C_CH2_data=FDC_read_reg(0x04)&0xFFF;
		     C_CH2_data_low = FDC_read_reg(0x05);
		     C_CH2_data_final =((C_CH2_data<<16)+C_CH2_data_low);
				
//读通道3数值		 
			delay_ms(50);
		     C_CH3_data=FDC_read_reg(0x06)&0xFFF;
		     C_CH3_data_low = FDC_read_reg(0x07);
		     C_CH3_data_final =((C_CH3_data<<16)+C_CH3_data_low);
				}

上面的就是读取相对应的数值移位赋值给C_CHX_data_final这一个变量。因为在FDC2214的芯片上是有四个通道的,可以同时读取各通道的数值,而且还很精准,这一个芯片还是很厉害的。

然后就是对返回来的数值进行处理真正读出该状态下的电容值。
至于是怎么计算电容值的我就不解释了,贴个文章各位看吧,计算电容值

我用的计算电容函数
float Cap;
	Data_FDC = FCD2214_ReadCH(index);
//	Cap = 56645.763f/((float)Data_FDC);
//	return ((Cap*Cap)-33);
	Cap = 232021045.248/(Data_FDC);
	return (Cap*Cap);

总结

这一道电赛题是不难的,读取纸张的电容值,通过函数拟合得出最合适的电容值,然后就是和查表法对比就行了。最后就是如果你的FDC2214读取出来的数据是65535或者是其他一些很奇怪的数值,检查一下接线,如果还是不行的话看一下代码是不是哪一个寄存器配置有问题。没啥好说的,第一次写博客,写的不是很好,见谅了各位,代码在我资源那里贴出来,ヾ(^ ▽ ^*)))!!!!!

  • 24
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 23
    评论
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐乐小工厂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值