Blind Box Recognition Device-2022TI Cup October League Question D

foreword

   In order to prepare for the 2023 national competition, in the October league competition of the 2022TI Cup, the blind box recognition device of the D question was selected as the training topic. During the period, I inquired about a lot of metal detection methods, basically detecting metals through electromagnetic induction, by comparing the different influences of different metals on the inductance of the coil, adding an oscillation circuit to measure the oscillation frequency, and then comparing different coins.
   TI company has provided the digital converter specially used in the inductance measurement. This article chooses LDC1314 as the detection chip, through the different effects of different coins on the LC oscillator circuit, different data are read by the single-chip microcomputer to identify the coin.
   In the process of completing the topic, I queried many driver codes of LDC1314, but basically they are not controlled by bare chips and MSP430F5529 microcontrollers. After several modifications, the data reading of LDC1314 is completed. This article focuses on the MSP430F5529 software reading code for the chip. A link to the CCS project file is given at the end of the article.
   This code shows that the LCD12864 LCD screen is used for display, and the board is the smallest development board. The screen code is no longer given in the article, and there are related instructions in the CCS project file.

Overall Program Description

   This system uses MSP430F5529 as the control core, designs and manufactures a blind box identification device, realizes the detection of the presence or absence of blind boxes, and then judges the types and placement methods of coins in different types of blind boxes through electromagnetic detection technology. The system judges whether there is a blind box by turning on and off the LED light of the photosensitive sensor. When a blind box is detected, the resonant frequency of the LC oscillator changes. The system uses the LDC1314 sensor to measure the resonant frequency of the LC oscillator. Different resonant frequencies correspond to different types of blind boxes, and then determine the type and placement of coins in the blind box. The system displays "Yes" and "No" of the blind box in the sensing area through the OLED screen of the expansion board, as well as the working status. After the recognition is completed, it can display the recognition completion, coin type and coin combination.
   The physical picture of all the hardware is shown in the figure below:

LDC1314 module schematic diagram

   The schematic diagram of the LDC1314 module is roughly shown in the figure below:
LDC1314 module
   Since there is already a 100pF capacitor connected to the channel in the module, you need to pay attention to the value of the capacitor when connecting the LC sensor later.
   This module is ready-made in Taobao, it is recommended to buy this module directly: LDC1314 adapter board .
   It is not recommended to solder this module by yourself (the lesson of my own blood and tears). First, the chip package is WQFN(RGH)|16, and the chip pins are all on the bottom, so it is difficult to solder by hand; second, the PCB data needs to be drawn and printed by yourself, and the cycle is very long.

Approximate hardware connection

   The hardware is mainly an LDC1314 module and a photoelectric sensor module. The photoelectric sensor module should be available for a few dollars on Taobao, mainly with a VDD power interface, a GND interface and a DO digital output interface, and the analog interface AO does not need to be connected. Use 5529 to read the digital output interface and judge whether there is a blind box or not; LDC1314 needs to use I2C communication pins SCL and SDA, I2C address selection terminal ADDR, and working status pin SD.
  LDC1314CLKIN uses an external 40M clock.

Introduction of LDC1314

   LDC1314 reads the oscillation frequency of the LC oscillator, converts it into a corresponding 12-bit digital quantity, and reads the data through I2C communication.
   This article introduces the function and connection of each pin of LDC1314, the link is here: LDC1314 Chinese pin description .
   This article introduces the use of LDC1314, each process. And the meaning of some registers. The use of LDC1314 .
   Both articles are Chinese translations of the LDC1314 data sheet on TI's official website. More specific usage methods can be found directly in the data sheet.

Drive LDC1314 with MSP430F5529 (code)

driver code

   The specific I2C communication code writing method will not be introduced here. If necessary, you can search for I2C communication to learn about it. Directly give all the codes of the LDC1314 driver.

The ldc1314.h file is as follows:

#ifndef SRC_LDC1314_H_
#define SRC_LDC1314_H_

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;

extern unsigned int SENSOR_CH;              //数组声明 存储四个通道的电感线圈采样值

//PORT_SET
#define SCL_DIR  P6DIR |=BIT1
#define SDA_DIR  P6DIR |=BIT2
#define ADDR_DIR P6DIR|=BIT3
#define SD_DIR   P6DIR|=BIT5

#define ADDR_0 P6OUT&=~BIT3
#define SD_0   P6OUT&=~BIT5
#define SCL1 P6OUT |=BIT1
#define SCL0 P6OUT &=~BIT1
#define SDA1 P6OUT |=BIT2           //IIC数据引脚
#define SDA0 P6OUT &=~BIT2
#define SDAIN P6DIR &=~BIT2
#define SDAOUT P6DIR |=BIT2
#define SDADATA (P6IN & BIT2)


// I2C
void I2C_INIT(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(void);
void IIC_NAck(void);
unsigned char IIC_Wait_Ack(void);
unsigned char IIC_Read_Byte(unsigned char ack);
void IIC_Send_Byte(unsigned char txd);
unsigned int Single_Write(unsigned char SlaveAddress,unsigned char REG_Address,unsigned int REG_data);
unsigned char Single_Read(unsigned char SlaveAddress,unsigned char REG_Address,unsigned int *Read);

// LDC1314 COMMANDS
#define LDC13xx16xx_CMD_DATA_MSB_CH0          0x00
#define LDC13xx16xx_CMD_DATA_LSB_CH0          0x01
#define LDC13xx16xx_CMD_DATA_MSB_CH1          0x02
#define LDC13xx16xx_CMD_DATA_LSB_CH1          0x03
#define LDC13xx16xx_CMD_DATA_MSB_CH2          0x04
#define LDC13xx16xx_CMD_DATA_LSB_CH2          0x05
#define LDC13xx16xx_CMD_DATA_MSB_CH3          0x06
#define LDC13xx16xx_CMD_DATA_LSB_CH3          0x07
#define LDC13xx16xx_CMD_REF_COUNT_CH0         0x08     //参考计数设置
#define LDC13xx16xx_CMD_REF_COUNT_CH1         0x09
#define LDC13xx16xx_CMD_REF_COUNT_CH2         0x0A
#define LDC13xx16xx_CMD_REF_COUNT_CH3         0x0B
#define LDC13xx16xx_CMD_OFFSET_CH0          0x0C     //补偿值
#define LDC13xx16xx_CMD_OFFSET_CH1          0x0D
#define LDC13xx16xx_CMD_OFFSET_CH2          0x0E
#define LDC13xx16xx_CMD_OFFSET_CH3          0x0F
#define LDC13xx16xx_CMD_SETTLE_COUNT_CH0      0x10     //解决参考计数
#define LDC13xx16xx_CMD_SETTLE_COUNT_CH1    0x11
#define LDC13xx16xx_CMD_SETTLE_COUNT_CH2      0x12
#define LDC13xx16xx_CMD_SETTLE_COUNT_CH3      0x13
#define LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0  0x14     //参考和传感器分频设置
#define LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH1  0x15
#define LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH2  0x16
#define LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH3  0x17
#define LDC13xx16xx_CMD_STATUS              0x18
#define LDC13xx16xx_CMD_ERROR_CONFIG        0x19     //错误报告配置
#define LDC13xx16xx_CMD_CONFIG              0x1A     //转换配置
#define LDC13xx16xx_CMD_MUX_CONFIG          0x1B     //通道复用
#define LDC13xx16xx_CMD_RESET_DEVICE        0x1C     //复位设备
#define LDC13xx16xx_CMD_SYSTEM_CLOCK_CONFIG 0x1D     //
#define LDC13xx16xx_CMD_DRIVE_CURRENT_CH0     0x1E     //当前驱动设置
#define LDC13xx16xx_CMD_DRIVE_CURRENT_CH1   0x1F     //
#define LDC13xx16xx_CMD_DRIVE_CURRENT_CH2   0x20     //
#define LDC13xx16xx_CMD_DRIVE_CURRENT_CH3     0x21     //
#define LDC13xx16xx_CMD_MANUFACTID          0x7E     //制造商ID
#define LDC13xx16xx_CMD_DEVID                 0x7F     //设备ID

#define EVM_MIN_I2CADDR     0x2A
#define EVM_MAX_I2CADDR     0x2B
#define EVM_DEFAULT_I2CADDR  EVM_MIN_I2CADDR                        //EVM_MIN_I2CADDR
#define EVM_DEFAULTS_SIZE 24 // 13 registers, 0x08 - 0x14



void LDC1314_INIT(void);
void LDC1314_Read(void);


#endif /* SRC_LDC1314_H_ */

The ldc1314.c file is as follows:

#include <msp430.h>
#include "ldc1314.h"
typedef unsigned char u8;
unsigned int SENSOR_CH;                //存储四个通道的电感线圈采样值
static uint8_t default_addr;

#define CPU_F ((double)1000000)
#define DelayMS(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))    //宏定义延时函数
#define IIC_Delay(x) {
      
       unsigned char y; y = x; while(--y);}

//I2C start/
unsigned char I2C_SDA_READ()
{
    
    
    unsigned char s;
    SDAIN;
    s=SDADATA;
    SDAOUT;
    return s;
}

void I2C_INIT(void)
{
    
    

}


/*******************************************************************************
* Function Name  : IIC_Start
* Description    : Master Start Simulation IIC Communication
* Input          : None
* Output         : None
* Return         : Wheather  Start
****************************************************************************** */
void IIC_Start(void)
{
    
    
    SDA1;
    SCL1;
    IIC_Delay(7);
    IIC_Delay(7);
    SDA0; ;
    IIC_Delay(7);
    SCL0;
}
/*******************************************************************************
* Function Name  : IIC_Stop
* Description    : Master Stop Simulation IIC Communication
* Input          : None
* Output         : None
* Return         : None
****************************************************************************** */
void IIC_Stop(void)
{
    
    
    SCL0;
    SDA0;//STOP:when CLK is high DATA change form low to high
    IIC_Delay(7);
    SCL1;
    SDA1;//??I2C??????
    IIC_Delay(7);
}

/*******************************************************************************
* Function Name  : IIC_Ack
* Description    : Master Send Acknowledge Single
* Input          : None
* Output         : None
* Return         : None
****************************************************************************** */
void IIC_Ack(void)
{
    
    
    SDA0;
    IIC_Delay(7);
    SCL1;
    IIC_Delay(7);
    SCL0;
    SDA1;
    IIC_Delay(1);
    SDA0;
    SCL0;
}
/*******************************************************************************
* Function Name  : IIC_NAck
* Description    : Master Send No Acknowledge Single
* Input          : None
* Output         : None
* Return         : None
****************************************************************************** */
void IIC_NAck(void)
{
    
    
    SCL0;
    SDA1;
    IIC_Delay(7);
    SCL1;
    IIC_Delay(7);
    SCL0;
    SDA0;
}

/*******************************************************************************
* Function Name  : I2C_Wait_Ack
* Description    : Master Reserive Slave Acknowledge Single
* Input          : None
* Output         : None
* Return         : Wheather  Reserive Slave Acknowledge Single
****************************************************************************** */
unsigned  char IIC_Wait_Ack(void)
{
    
    
    unsigned int ucErrTime = 0;
    SDA1;
    IIC_Delay(7);
    SCL1;
    IIC_Delay(7);

    while(I2C_SDA_READ())
    {
    
    
        ucErrTime++;
        if(ucErrTime>250)
        {
    
    
            IIC_Stop();
            return 1;
        }
    }
    SCL0;
    SDA0;
    IIC_Delay(7);
    return 0;
}

/*******************************************************************************
* Function Name  : IIC_Send_Byte
* Description    : Master Send a Byte to Slave
* Input          : Will Send Date
* Output         : None
* Return         : None
****************************************************************************** */
void IIC_Send_Byte(unsigned  char Dat)
{
    
    
    unsigned  char t;

    for(t=0;t<8;t++)
    {
    
    
                if(Dat & 0x80)
                {
    
    
                    SDA1;
                }
                else
                {
    
    
                    SDA0;
                }
        Dat<<=1;
                IIC_Delay(7);
                SCL1;
                IIC_Delay(7);
                SCL0;
    }
}
/*******************************************************************************
* Function Name  : I2C_Read_Byte
* Description    : Master Reserive a Byte From Slave
* Input          : None
* Output         : None
* Return         : Date From Slave
****************************************************************************** */
unsigned  char IIC_Read_Byte(unsigned char ack)
{
    
    
        unsigned char i,receive=0;

        SDA1;
        for(i=0;i<8;i++ )
        {
    
    
            SCL0;
            IIC_Delay(7);
            SCL1;
            IIC_Delay(3);
      receive<<=1;
      if(I2C_SDA_READ())receive++;
            IIC_Delay(3);
            SCL0;
    }
    if (!ack)
        IIC_NAck();
    else
        IIC_Ack();
    return receive;
}
//ZRX
//单字节写入*******************************************

uint16_t Single_Write(unsigned  char SlaveAddress, unsigned  char REG_Address,uint16_t REG_data)             //void
{
    
    
        static unsigned  char buffer[2];

        buffer[0] = (REG_data >> 8);
        buffer[1] = (unsigned  char)(REG_data & 0x00ff);

    IIC_Start();

    IIC_Send_Byte(SlaveAddress << 1);

    if (IIC_Wait_Ack() == 1)
        {
    
    
            return 0;
        }

    IIC_Send_Byte(REG_Address);
        if (IIC_Wait_Ack() == 1)
        {
    
    
            return 0;
        }

        IIC_Send_Byte(buffer[0]);
        if (IIC_Wait_Ack() == 1)
        {
    
    
            return 0;
        }

        IIC_Send_Byte(buffer[1]);
        if (IIC_Wait_Ack() == 1)
        {
    
    
            return 0;
        }

        IIC_Stop();

        return 1;
}


//单字节读取*****************************************
unsigned char Single_Read(unsigned  char SlaveAddress, unsigned  char reg_add,unsigned int *Read)
{
    
    
    unsigned  char Dat_L = 0;
    unsigned  char Dat_H = 0;

    /* 器件地址 */
    IIC_Start();
    IIC_Send_Byte(SlaveAddress << 1);
    if (IIC_Wait_Ack() == 1)
    {
    
    
        return 0;
    }

    /* 寄存器地址 */
    IIC_Send_Byte(reg_add);
    if (IIC_Wait_Ack() == 1)
    {
    
    
        return 0;
    }

    /* 器件地址(读)*/
    IIC_Start();

    IIC_Send_Byte((SlaveAddress << 1) + 1);
    if (IIC_Wait_Ack() == 1)
    {
    
    
        return 0;
    }


    Dat_H = IIC_Read_Byte(1);   //ack
    Dat_L = IIC_Read_Byte(0);   //Nack

    IIC_Stop();

    *Read = ((Dat_H << 8) | Dat_L);

    return 1;
}
//I2C/




/***************************************
 * 函数名:InitLDC1314
 * 描述  :初始化LDC1314
 * 输入  :无
 * 输出  :无
 ***************************************/
void LDC1314_INIT(void)
{
    
    
    uint8_t retVal=1;     //执行错误标志

    //IO_SET
    SCL_DIR  ;
    SDA_DIR  ;
    ADDR_DIR ;
    SD_DIR   ;

    //init begin
    ADDR_0;
    default_addr = EVM_DEFAULT_I2CADDR;
    SD_0;
    Single_Write(default_addr,LDC13xx16xx_CMD_RESET_DEVICE,0x8000);
    DelayMS(10);                  //此处延时10MS
    do
    {
    
    
        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH0,0x04D6);     // 4 clock periods
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH1,0xFFFF);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH2,0xFFFF);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH3,0xFFFF);

        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_OFFSET_CH0,0x0000);        //补偿值
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_OFFSET_CH1,0x0000);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_OFFSET_CH2,0x0000);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_OFFSET_CH3,0x0000);

        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH0,0x000A);  // 1 clock period
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH1,0x0400);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH2,0x04FF);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH3,0x0400);

        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0,0x1001); // 1000
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH1,0x0000);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH2,0x0000);
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH3,0x0000);

        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_STATUS,0x0000); // report only DRDYs to INT
        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_CONFIG,0x1601); // CLKIN pin1281
        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_MUX_CONFIG,0x020D); // ch0, ch1,ch2,ch3-> Wipro for 4 ch
        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_SYSTEM_CLOCK_CONFIG,0x0200); // default, divide by 2

        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH0,0xF000); //
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH1,0x0000); //
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH2,0x0000); //
//        retVal &= Single_Write(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH3,0x0000); //
    }while(retVal==0);         //若执行出错,则继续循环初始化

}
/***************************************
 1. 函数名:LDC1314_Read
 2. 描述  :读取寄存器数据
 3. 输入  :无
 4. 输出  :无
 **************************************/
void LDC1314_Read()
{
    
    
    uint8_t retVal;
    do
    {
    
    
      retVal = 1;
      retVal &= Single_Read(default_addr,LDC13xx16xx_CMD_DATA_MSB_CH0,&SENSOR_CH);
//      retVal &= Single_Read(default_addr,LDC13xx16xx_CMD_DATA_MSB_CH1,&SENSOR_CH[1]);
//      retVal &= Single_Read(default_addr,LDC13xx16xx_CMD_DATA_MSB_CH2,&SENSOR_CH[2]);
//      retVal &= Single_Read(default_addr,LDC13xx16xx_CMD_DATA_MSB_CH3,&SENSOR_CH[3]);
    }while( retVal == 0);
    //消除四个通道之间本身存在的采样误差值,归一化处理
//    SENSOR_CH[0]+=2;
//    SENSOR_CH[1]+=3;
//    SENSOR_CH[2]+=3;
//    SENSOR_CH[3]+=3;
}

An example main function is as follows:

#include <msp430.h>
#include "ldc1314.h"
#define SlaveAddress 0x2A   //ADDR需要接地
unsigned int i=0;
unsigned int temp=0;  //传感器结果

int main(void)
 {
    
    
    WDTCTL = WDTPW | WDTHOLD;     // Stop watchdog timer
    SCL_DIR  ;   //6.1
    SDA_DIR  ;   //6.2
    ADDR_DIR ;   //6.3
    SD_DIR   ;   //6.5
    LDC1314_INIT();                //LDC1314初始化后需要延时

      _delay_cycles(1000000);      //1s  ldc线圈工作安全时间
  	LDC1314_Read();
    while(1)
  {
    
    

                for(i=0;i<20;i++)
                {
    
    
                    LDC1314_Read();
                    temp=temp+SENSOR_CH;
                    if(i==19)
                    {
    
    
                        temp=temp/20;
                    }
                }
                temp=0;
  }
  return 0;
 }

After the code runs, you should be able to read the sensor output results in temp.

Code Usage Instructions

1. The code first needs to use the LDC1314_INIT() function to initialize. The initialization in this code is for CH0 single-channel detection. The control of LDC1314 can be configured and modified according to the link or data manual of LDC1314 given above.
2. The LDC1314_Read() function is to read the detection data, and the read result is in SENSOR_CH().

Improvement

   In the process of completion, only blind box A and blind box B are recognized, and the recognition effect of blind box B is not ideal. The following aspects can be improved:
1. The design of the LC sensor coil, it is recommended to design the coil a little larger when generating the adapted LC sensor provided by Ti, at least the radius should be larger than the maximum radius of the recognized coin.
2. Choose to use the LDC1614 chip as the inductance detection chip. The use of this chip is exactly the same as that of the LDC1314, but the measurement accuracy is higher, and it may be able to better identify the differences between different coins.

Full project file link

Baidu network disk link: https://pan.baidu.com/s/14ISwsRxe3vFO6HXqM75A4Q?pwd=o7nv
Extraction code: o7nv
   display uses LCD12864, you can change the relevant display code according to your own screen.

Guess you like

Origin blog.csdn.net/qq_55600803/article/details/127573781