2016TI杯——寻迹小车

2016TI杯——寻迹小车首先,我选择的是B题————自动循迹小车,具体如下:B题:自动循迹小车1.任务设计制作一个自动循迹小车。小车采用一片TI公司LDC1314或LDC1000电感数字转换器作为循迹传感器,在规定的平面跑道自动按顺时针方向循迹前进。跑道的标识为一根直径0.6~0.9mm的细铁丝,按照图1的示意尺寸,用透明胶带将其贴在跑道上。图中所有圆弧的半径均为为20cm±2cm。图1跑道示意图

大家好,又见面了,我是你们的朋友全栈君。

首先,我选择的是B题————自动循迹小车,具体如下:

B题:自动循迹小车
1.任务
设计制作一个自动循迹小车。小车采用一片 TI公司LDC1314或LDC1000电感数字转换器作为循迹传感器,在规定的平面跑道自动按顺时针方向循迹前进。跑道的标识为一根直径0.6~0.9mm的细铁丝,按照图1的示意尺寸,用透明胶带将其贴在跑道上。图中所有圆弧的半径均为为20cm±2cm。
这里写图片描述
图1 跑道示意图
2.要求
(1)在图1小车所在的直线区任意指定一起点(终点),小车依据跑道上设置的铁丝标识,自动绕跑道跑完一圈。时间不得超过10分钟。小车运行时必须保持轨迹铁丝位于小车垂直投影之下。如有越出,每次扣2分。 (40分)
(2)实时显示小车行驶的距离和运行时间。 (10分)
(3)在任意直线段铁丝上放置4个直径约19mm的镀镍钢芯硬币(第五套人民币的1角硬币),硬币边缘紧贴铁丝,如图1所示。小车路过硬币时能够发现并发出声音提示。 (20分)
(4)尽量减少小车绕跑道跑完一圈运行时间。 (25分)
(5)其他。 ( 5分)
(6)设计报告 (20分)
项 目 主要内容 满分
方案论证 比较与选择,方案描述 3
理论分析与计算 系统相关参数设计 5
电路与程序设计 系统组成,原理框图与各部分的电路图,系统软件与流程图 5
测试方案与测试结果 测试结果完整性,测试结果分析 5
设计报告结构及规范性 摘要,正文结构规范,图表的完整与准确性 2
总 分 20
这里写图片描述

3.说明
(1)自动循迹小车允许用玩具车改装。小车用自带电池供电运行,不能使用外接电源。小车的尺寸为其在地面的投影不超过A4纸大小。小车自动运行后,不得有任何人工干预小车运动的行为,如遥控等。
(2)电感传感器除了使用TI公司配发的LDC1314芯片外,也可使用LDC1000芯片或模块,数量也仅限一只。不得使用任何其他类型的传感器用于循迹。
(3)跑道除指定的铁丝外,不得另外增加任何标记。跑道附近不应有其他额外金属物体。

直入主题:大家都知道比赛要用到的主要器件会提前通知,梁比赛之前搭好了小车并且调试好了LDC1000。然题目出来之后,我们决定采用ldc1314(因为只能用一块探测芯片,事后才发现这是一个多么错误的决定)至于小车本身我就不过多涉及,很普通的一个小车。几个重要模块:
一:电源模块
二:核心板
三:金属轨道探测模块(ldc1000或者ldc1314)
正如前面所言,比赛开始后我们放弃了调好的ldc1000改用了ldc1314,好在有ldc1000的经验,第一天我们小组做出了ldc1000的模块,也写好了相应的驱动代码。然后就开始调试小车寻迹,用了PID算法,按照P,D,I的顺序调的。途中由于用的开关电源而没有加保险管,在熬夜过程中不小心把电源接反了而烧了2576开关电源芯片(也不知道加了保险管是否真的就保险,但是后面加了保险管再也没烧过了,毕竟比赛,最好不要节外生枝)就这样在第三天早上我们调好了PID,小车能勉强走完全程完成寻迹了,心里那个激动啊,就这样我们继续修改PID参数,力求更好的效果。但第四天早上起来,不知道怎么回事把LDC1314烧了,不明不白的也不知道哪里出问题了。最悲哀就是学校老师不再给我们LDC1314。失望之后,我拿出了LDC1000,还是用ldc1000,一开始不用ldc1000是因为它只有一个通道——只能接一个线圈,而LDC1314有四个通道——能接四个线圈,所以LDC1314在寻迹上被我们理所当然的认为更好了,然而时候经过查阅datasheet和实际验证以及比赛群里的同学反映,LDC1314检测距离和灵敏度明显小于LDC1000。正式因为如此ldc’1000也是很多成功者的选择,因为ldc’1314实在是太短了,稍微数据丢失(它没有检测到)车就很容易出轨道了。从第四天开始,我们改用LDC1000——方案有二:
一:用一个线圈,利用PID来判断方向的转变(认识的一位非本校的师兄就是这样实现的),不过难点在于1,线圈要大一点,感应强度要强一些,2,小车要好控制(电机和舵机要好用)3,PID算法参数要选的非常好才行,不然很容易出轨道。
二:用两个线圈,安置在左和右用来判断方向,加上PID更可以精确一些控制。
由于我们用了直流电机(并没编码电机),其次舵机不怎么样,而且我没有好的大一点的线圈(学校老师打的PCB线圈效果极差!),担心一个线圈调不出来,所以我们采用两个线圈切换办法同样切换装置也是问题(一:用什么切换,二:切换频率对效果的影响)方案同样有二:1场管,2继电器。最终选择了继电器,频率改变小一些(的确·继电器对线圈采集的数据有一定影响,而且电流有一点变化),好在最终也算实现了。

总结几点:
一:熬夜一定要放慢动作,谨慎做事,很容易因为太困弄坏东西,得不偿失(比赛七天,前五天每天4点睡,八点起,后两天连续通宵)在很累很困的情况很容易弄错的,我们烧了1314和电源板很大原因就是太累太困又心急。
二:继电器驱动使用灌电流,不能使用拉电流(一开始怎么都驱动不了继电器,就连2003都不行,也是想不通,后来查资料找到了,卡了半天时间)
三:PID参数一定对应一个系统,系统变则参数变
四:使用SPI3的同时不能使用JTAG的复用时钟,需要关闭其复用时钟(具体我再研究研究,比赛当时使用SPI3一开始不顺利,关闭JTAG的复用时钟就ok了)
五:LDC1314和LDC1000的芯片可以改变检测的数值范围,调大差距值,但是我认为并不能改变灵敏度,而是通过调节线圈电感和连接的电容来改变灵敏度(具体可以见TI官网的在线计算工具)

最后就是一点遗憾了:第一:觉得自己准备不足,很多东西应该自己准备好的,尤其是小车,我很后悔用了一个性能太差的,直流电机(两边轮子相同电压转速还明显不一样),舵机小角度比较差,要么不转,要么转大角度。其他就是线圈我很后悔没有自己打,学校打那个确实太差,有些根本就检测不大。第二:后悔放弃LDC1000,应为LDC1314确实检测距离在我那个硬件条件太短,几乎擦着地面走,LDC1000则还要好些,几乎是两倍的距离吧,说实话一开始以为TI推销他的新出的1314就很在意这个。事实证明在硬件不太好的情况下,LDC1000还好弄一点·。第三:熬夜不要急,血的教训。

下面给出部分代码:

include

include “usart.h”

include “ldc1000.h”

include “1602.h”

include “beep.h”

include “delay.h”

include “motor.h”

include “pwm_tim5.h”

include “step_motor.h”

include “ldc_intruput.h”

include “pid.h”

extern unsigned long ProximityData; //LDC上Proximity Data
extern unsigned char flag;
extern u16 CCR3_Val , CCR4_Val ;//后轮2,3 舵机0

unsigned long red_ProximityData, bule_ProximityData;

void display(unsigned long temp,u16 adr);
void jichu_ProximityData(void);

unsigned long jichu_red,jichu_bule;
u16 time,distance;

uint8_t table[10]=”0123456789”;
uint8_t table1[10]=”Time:”;
uint8_t table2[10]=”distance:”;
extern u16 CCR3_Val;
u8 i;

int main (void)
{
NVIC_Configuration();
delay_init();
USART1_Config();
inct();
beep_Init();
SPI_LDC_Init();
TIM5_PWM_Init();
TIM7_ldc_Init(60000-1,72-1);
MOTOR_Init();
jidainqi_Init();

write_com(0x80);
delay(10);
for(i=0;i<6;i++)
write_data(table1[i]); 
write_com(0x80+0x0a);
write_data('s');
write_com(0x80+0x40);

for(i=0;i<9;i++)
write_data(table2[i]);
write_com(0x80+0x4e);
write_data(‘c’);
write_com(0x80+0x4f);
write_data(‘m’);

jichu_ProximityData();
Rear_wheel_direction(0);
while(1)
{
    if(jidianqi==0)              
    {
    LDCRead();
        if(ProximityData>9000&ProximityData<14000)
        {
                red_ProximityData=ProximityData;
        display(red_ProximityData,0x80+0x49);
        }
        else if(ProximityData<9000&ProximityData>8000)
        {
                            beep=1;
                    delay_ms(100);
                    beep=0;
        }
        else if(ProximityData<8000)
        {
            bule_ProximityData=ProximityData;

// display(bule_ProximityData,0x80+0x4F);
}
else if(ProximityData>=16000) //硬币
{
beep=1;
delay_ms(100);
beep=0;
}
delay_ms(50);
jidianqi=1;
}
else if(jidianqi==1)
{
LDCRead();
if(ProximityData>9000&ProximityData<14000)
{
red_ProximityData=ProximityData;
// display(red_ProximityData,0x80+0x49);
}
// else if(ProximityData<9000&ProximityData>8000)
// {
// beep=1;
// delay_ms(100);
// beep=0;
// }
else if(ProximityData<8000)
{
bule_ProximityData=ProximityData;
// display(bule_ProximityData,0x80+0x4F);
}
else if(ProximityData>16000) //硬币
{
beep=1;
delay_ms(100);
beep=0;
}
delay_ms(50);
jidianqi=0;
}

}
}
void display(unsigned long temp,u16 adr)
{
uint8_t i;
write_com(0x04);
delay(30);
write_com(adr);
while(temp)
{
i=temp%10;
write_data(table[i]);
temp/=10;
}
write_com(0x06);
}
void jichu_ProximityData() //获取基础值
{
u8 j;
for(j=0;j<10;j++)
{
if(jidianqi==0)
{
LDCRead();
if(ProximityData>9000&&ProximityData<18000)
{
red_ProximityData=ProximityData;
// display(red_ProximityData,0x80+0x49);
}
else if(ProximityData<9000)
{
bule_ProximityData=ProximityData;
// display(bule_ProximityData,0x80+0x4F);
}
else if(ProximityData>=18000) //硬币
{
beep=1;
delay_ms(100);
beep=0;
}
jidianqi=1;
delay_ms(100);
}
else if(jidianqi==1)
{
LDCRead();
if(ProximityData>9000&&ProximityData<18000)
{
red_ProximityData=ProximityData;
// display(red_ProximityData,0x80+0x49);
}
else if(ProximityData<9000)
{
bule_ProximityData=ProximityData;
// display(bule_ProximityData,0x80+0x4F);
}
else if(ProximityData>=18000) //硬币
{
beep=1;
delay_ms(100);
beep=0;
}
jidianqi=0;
delay_ms(100);
}
}
jichu_red=red_ProximityData;
jichu_bule=bule_ProximityData;
}

LDC1000驱动

ifndef LDC24L01_H

define LDC24L01_H

include

define GPIO_LDC GPIOC

define GPIO_LDC_CSN_Pin GPIO_Pin_5

define GPIO_LDC_CE_Pin GPIO_Pin_2

define GPIO_LDC_IQ_Pin GPIO_Pin_4

define SPI_NOP 0XFF//空指令用来读状态寄存器

/******寄存器地址区*********/

define LDC1000_CMD_REVID 0x00

define LDC1000_CMD_RPMAX 0x01

define LDC1000_CMD_RPMIN 0x02

define LDC1000_CMD_SENSORFREQ 0x03

define LDC1000_CMD_LDCCONFIG 0x04

define LDC1000_CMD_CLKCONFIG 0x05

define LDC1000_CMD_THRESHILSB 0x06

define LDC1000_CMD_THRESHIMSB 0x07

define LDC1000_CMD_THRESLOLSB 0x08

define LDC1000_CMD_THRESLOMSB 0x09

define LDC1000_CMD_INTCONFIG 0x0A

define LDC1000_CMD_PWRCONFIG 0x0B

define LDC1000_CMD_STATUS 0x20

define LDC1000_CMD_PROXLSB 0x21

define LDC1000_CMD_PROXMSB 0x22

define LDC1000_CMD_FREQCTRLSB 0x23

define LDC1000_CMD_FREQCTRMID 0x24

define LDC1000_CMD_FREQCTRMSB 0x25

// LDC BITMASKS

define LDC1000_BIT_AMPLITUDE 0x18

define LDC1000_BIT_RESPTIME 0x07

define LDC1000_BIT_CLKSEL 0x02

define LDC1000_BIT_CLKPD 0x01

define LDC1000_BIT_INTMODE 0x07

define LDC1000_BIT_PWRMODE 0x01

define LDC1000_BIT_STATUSOSC 0x80

define LDC1000_BIT_STATUSDRDYB 0x40

define LDC1000_BIT_STATUSWAKEUP 0x20

define LDC1000_BIT_STATUSCOMP 0x10

define TEST_RPMAX_MAX 0x13 /*< maximum calibration value for RPMAX /

define TEST_RPMAX_MIN 0x10 /*< minimum calibration value for RPMAX /

define TEST_RPMAX_INIT TEST_RPMAX_MIN+1 /*< RPMAX initial value /

define TEST_RPMIN_MAX 0x3D /*< maximum calibration value for RPMIN /

define TEST_RPMIN_MIN 0x3A /*< minimum calibration value for RPMIN /

define TEST_RPMIN_INIT TEST_RPMIN_MIN+1 /*< RPMIN initial value /

// Final Test Range

define TEST_RP_MSB_MAX 0x12 /*< maximum value for proximity data /

define TEST_RP_MSB_MIN 0x0A /*< minimum value for proximity data /

define TEST_FC_MAX 0x0D5D /*< maximum value for frequency counter /

define TEST_FC_MIN 0x0D39 /*< minimum value for frequency counter /

/******宏定义区*********/

define LDC_CSN_HIGH() GPIO_SetBits(GPIO_LDC, GPIO_LDC_CSN_Pin)

define LDC_CSN_LOW() GPIO_ResetBits(GPIO_LDC, GPIO_LDC_CSN_Pin) //csn置低

define LDC_Read_IRQ() GPIO_ReadInputDataBit (GPIO_LDC, GPIO_LDC_IQ_Pin)

/******函数声明区*********/
extern void SPI_LDC_Init(void);//spi的初始化
u8 SPI_LDC_RW(u8 data);
static void SPI_LDC_WriteReg(u8 reg,u8 data);//向reg寄存器中写入data
static u8 SPI_LDC_ReadReg(u8 reg);//读取指定状态寄存器的值
void LDC1000_init(void);
void LDCRead(void);
extern void MY_SPI_Init(void);
void TIM3_NVIC_Configuration(void);
static void TIM3_GPIO_Config(void);
static void TIM3_Mode_Config(void);
void TIM3_Init(void);
float CountRp(void);
unsigned long Fsensor(unsigned long lFcount);
unsigned long Fsensor(unsigned long lFcount);
unsigned long CountInductor(unsigned long lFsensor);

endif

include “ldc1000.h”

include “usart.h”

include “math.h”

define SPI_RWBIT 0x80

define Fext 32768 //32768 Hz

define ResponseTime 6144

define CapVal 0.0001 //1uF*/

unsigned long ProximityData;
unsigned long FrequencyData;
unsigned char flag;
volatile u32 speed=999;

__IO uint16_t DataRcv[5] ;

/*************初始化spi***********************
*功 能: 初始化野火的spi
*形 参: void
*返 回 值:void
*备 注:
*******************************************************/
extern void MY_SPI_Init(void)
{
SPI_InitTypeDef SPI_InitStr;
GPIO_InitTypeDef GPIO_InitStr;

/*使能GPIOB,GPIOD,复用功能时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);

/*使能SPI1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

/*对硬件stm32的SPI配置*/
/*配置 SPI_LDC_SPI的 SCK,MISO,MOSI引脚,GPIOA^5,GPIOA^6,GPIOA^7 */
GPIO_InitStr.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStr.GPIO_Mode = GPIO_Mode_AF_PP; //复用功能
GPIO_Init(GPIOA, &GPIO_InitStr);

/*对从机LDC24L01的控制角配置*/
/*配置CE引脚,GPIOA^2和 CSB 引脚*/
GPIO_InitStr.GPIO_Pin = GPIO_LDC_CSN_Pin;
GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStr.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStr);

/*对硬件stm32的SPI配置*/
/*配置SPI_LDC_SPI的IRQ引脚,GPIOA^3*/
GPIO_InitStr.GPIO_Pin = GPIO_LDC_IQ_Pin;
GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStr.GPIO_Mode = GPIO_Mode_IPU ;  //上拉输入
GPIO_Init(GPIOC, &GPIO_InitStr);

/* 这是自定义的宏,用于拉高csn引脚,LDC进入空闲状态 */
LDC_CSN_HIGH();

SPI_InitStr.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工
SPI_InitStr.SPI_Mode = SPI_Mode_Master;                     //主模式
SPI_InitStr.SPI_DataSize = SPI_DataSize_8b;                 //数据大小8位
SPI_InitStr.SPI_CPOL = SPI_CPOL_High;                       //时钟极性,空闲时为低
SPI_InitStr.SPI_CPHA = SPI_CPHA_2Edge;                      //第1个边沿有效,上升沿为采样时刻
SPI_InitStr.SPI_NSS = SPI_NSS_Soft;                         //NSS信号由软件产生
SPI_InitStr.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;  //8分频,9MHz
SPI_InitStr.SPI_FirstBit = SPI_FirstBit_MSB;                //高位在前
SPI_InitStr.SPI_CRCPolynomial = 7;                          //CRC校验复位
SPI_Init(SPI1, &SPI_InitStr);

/* Enable SPI1  */
SPI_Cmd(SPI1, ENABLE);

}

/*************向LDC中读/写一个字节*************
*功 能: 向LDC中读/写一个字节
*形 参: 写入的数据
*返 回 值: 读取得的数据
*备 注:
*******************************************************/
u8 SPI_LDC_RW(u8 data) //向LDC中读写一个字节
{
/* 当 SPI发送缓冲器非空时等待 */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

/* 通过 SPI2发送一字节数据 */
SPI_I2S_SendData(SPI1, data);

 /* 当SPI接收缓冲器为空时等待 */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI1);

}

/*************向LDC指定的寄存器写值*************
*功 能: 向LDC指定的寄存器写值
*形 参: reg:LDC的命令+寄存器地址。
* data:将要向寄存器写入的数据
*返 回 值: 寄存器的状态
*备 注:
*******************************************************/
static void SPI_LDC_WriteReg(u8 reg,u8 data)
{

// LDC_CE_LOW();//进入待机模式1,低功耗模式,此模式下LDC可以接收数据
LDC_CSN_LOW();//拉低csn片选信号,使能LDC的spi传输

SPI_LDC_RW(reg);//向LDC发送命令和寄存器的号

SPI_LDC_RW(data);//向刚才指定的寄存器写入数据

LDC_CSN_HIGH();//拉高csn片选信号,即释放LDC的spi传输完毕;

}

/*************读取LDC指定的寄存器值*************
*功 能: 读取LDC指定的寄存器值
*形 参: reg:LDC寄存器地址。
*返 回 值: 状态寄存器的数据
*备 注:
*******************************************************/
static u8 SPI_LDC_ReadReg(u8 reg)
{
u8 Reg_Value;

// LDC_CE_LOW();//进入待机模式1,低功耗模式,此模式下LDC可以接收数据
LDC_CSN_LOW();//拉低csn片选信号,使能LDC的spi传输

SPI_LDC_RW(reg|SPI_RWBIT);//选择寄存器
Reg_Value = SPI_LDC_RW(SPI_NOP);

LDC_CSN_HIGH();//拉高csn片选信号,即释放LDC的spi传输完毕;

return Reg_Value;

}

/**********************************************************
* @brief: LDC1000初始化配置,ps:在SPI中配置了数据位16个数据长度,故
* 在发送数据时可以将地址和值进行或运算一起发送出去
* @param: none
* @return: none
***********************************************************/
void LDC1000_init(void)
{
// SPI_Write(LDC1000_CMD_RPMAX<<8|0xff);
SPI_LDC_WriteReg(LDC1000_CMD_RPMAX,0x31); //配置Rp_MAX(0x01)寄存器
SPI_LDC_WriteReg(LDC1000_CMD_RPMIN,0x1b); //配置Rp_MIN(0x02)寄存器
SPI_LDC_WriteReg(LDC1000_CMD_SENSORFREQ,0x94); //配置Sensor Frequency(0x03)寄存器
SPI_LDC_WriteReg(LDC1000_CMD_LDCCONFIG,0x17); //配置LDC Configuration(0x04)寄存器
SPI_LDC_WriteReg(LDC1000_CMD_CLKCONFIG,0x00); //配置Clock Configuration(0x05)寄存器,
//使用TBCLK作为时钟源 //配置INTB为比较输出标志位(status of Comparator output)
SPI_LDC_WriteReg(LDC1000_CMD_THRESHILSB,0x50); //配置Comparator Threshold High(0x06)寄存器低8位
SPI_LDC_WriteReg(LDC1000_CMD_THRESHIMSB,0x14); //配置Comparator Threshold High(0x07)寄存器高8位
SPI_LDC_WriteReg(LDC1000_CMD_THRESLOLSB,0xC0); //配置Comparator Threshold Low(0x08)寄存器低8位
SPI_LDC_WriteReg(LDC1000_CMD_INTCONFIG,0x02); //配置INTB Pin Configuration(0x0A),
SPI_LDC_WriteReg(LDC1000_CMD_PWRCONFIG,0x01); //配置Power Configuration(0x0B)寄存器, //为Active Mode,使能转化
}

/**********************************************************
* @brief: 使用SPI读取LDC1000中的数据
* @param: none
* @return: none
***********************************************************/
void LDCRead(void)
{
// LDC_CSN_LOW();
ProximityData = 0;
FrequencyData = 0;
while(LDC_Read_IRQ()!=0)
printf(“read 1 failed!”);
DataRcv[0] = SPI_LDC_ReadReg(LDC1000_CMD_PROXLSB); //写入将要读取的Proximity Data LSB寄存器地址(0x21)
//printf(“0 %d\r\n”,DataRcv[0]);
//SPI_Read(&DataRcv[0]); //读取上述寄存器中的值,并存入DataRcv[0]
ProximityData|= DataRcv[0] ;
while(LDC_Read_IRQ()!=0)
printf(“read 2 failed!”);
DataRcv[1] = SPI_LDC_ReadReg(LDC1000_CMD_PROXMSB); //写入将要读取的Proximity Data MSB寄存器地址(0x22)
//printf(“1 %d\r\n”,DataRcv[1]);
//SPI_Read(&DataRcv[1]); //读取上述寄存器中的值,并存入DataRcv[1]
ProximityData|= (DataRcv[1]<<8) ; //组合成ProximityData
while(LDC_Read_IRQ()!=0)
printf(“read 3 failed!”);
DataRcv[2] = SPI_LDC_ReadReg(LDC1000_CMD_FREQCTRLSB); //写入将要读取的Frequency Counter Data LSB寄存器地址(0x23)
//printf(“2 %d\r\n”,DataRcv[2]);
//SPI_Read(&DataRcv[2]); //读取上述寄存器中的值,并存入DataRcv[2]
FrequencyData|= DataRcv[2] ;
while(LDC_Read_IRQ()!=0)
printf(“read 4 failed!”);
DataRcv[3] = SPI_LDC_ReadReg(LDC1000_CMD_FREQCTRMID); //写入将要读取的Frequency Counter Data Mid-Byte寄存器地址(0x24)
//printf(“3 %d\r\n”,DataRcv[3]);
//SPI_Read(&DataRcv[3]); //读取上述寄存器中的值,并存入DataRcv[3]
FrequencyData|= (DataRcv[3]<<8) ;
while(LDC_Read_IRQ()!=0);
DataRcv[4] = SPI_LDC_ReadReg(LDC1000_CMD_FREQCTRMSB); //写入将要读取的Frequency Counter Data MSB寄存器地址(0x25)
//printf(“4 %d\r\n\n\n”,DataRcv[4]);
//SPI_Read(&DataRcv[4]); //读取上述寄存器中的值,并存入DataRcv[4]
FrequencyData|= (DataRcv[4]<<16) ; //组合成FrequencyData

// LDC_CSN_HIGH();
}
//——————————————————//
//———————-Rp 计算————————-//
//————-unsigned long CountRp() —————–//
//——————————————————//
float CountRp(void)
{
float Y;
unsigned Code;
float Rp;

Code =ProximityData;

Y = ((float)Code/32768.0);
printf(“Y value: %f\r\n”,Y);
Rp = (float)(((float)TEST_RPMAX_MAX*(float)TEST_RPMAX_MIN) / ((float)TEST_RPMAX_MIN*(1-Y)+(float)TEST_RPMAX_MAX*(float)Y));

return Rp;
}

//——————————————————//
//——————-LC震荡频率求值——————–//
//—–unsigned long Fsensor(unsigned long lFcount)—–//、
//输入参数:lFcount: Fre Code的值
//——————————————————//
unsigned long Fsensor(unsigned long lFcount)
{
unsigned long lFsensor;
unsigned long Fcount;

Fcount = lFcount;
lFsensor = (1*Fext*ResponseTime)/(3*Fcount);

return lFsensor;
}
//——————————————————//
//———————L电感求值———————-//
//–unsigned long CountInductor(unsigned long lFsensor)-//
//输入参数:lFsensor: LC谐振频率
//——————————————————//
unsigned long CountInductor(unsigned long lFsensor)
{
unsigned long Fsensor;
unsigned long L;

Fsensor = lFsensor;

L = (unsigned long)(pow(10,12)* 1/(CapVal * pow(2*3.14*Fsensor,2)) ); //uH

return L;
}
extern void SPI_LDC_Init(void)
{
TIM3_Init();
MY_SPI_Init();
LDC1000_init();
flag=1;
}

/*
* 函数名:TIM3_NVIC_Configuration
* 描述 :TIM3中断优先级配置
* 输入 :无
* 输出 :无
*/
void TIM3_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);                                                     
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;   
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

}

static void TIM3_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

}

static void TIM3_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

/* PWM信号电平跳变值 */
u16 TIM_CCR3_Val = 2;  

/* -----------------------------------------------------------------------
TIME3 可以输出 4 路 PWM 波形:
TIME3_CH1   ------  PA6
TIME3_CH2   ------  PA7
TIME3_CH3   ------  PB0
TIME3_CH4   ------  PB1
----------------------------------------------------------------------- */

/* Time base configuration */        
TIM_TimeBaseStructure.TIM_Period = 3;       //当定时器从0计数到999,即为1000次,为一个定时周期
TIM_TimeBaseStructure.TIM_Prescaler = 0;        //设置预分频:预分频72,即为1KHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;    //设置时钟分频系数:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM3, TIM_FLAG_Update);                                       /* 清除溢出中断标志 */
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);

/* PWM1 Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;       //配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   
TIM_OCInitStructure.TIM_Pulse = TIM_CCR3_Val;      //设置跳变值,当计数器计数到这个值时,电平发生跳变
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //当定时器计数值小于CCR1_Val时为高电平

TIM_OC3Init(TIM3, &TIM_OCInitStructure);     //使能通道1

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;       //配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   
TIM_OCInitStructure.TIM_Pulse = TIM_CCR3_Val;      //设置跳变值,当计数器计数到这个值时,电平发生跳变
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //当定时器计数值小于CCR1_Val时为高电平

TIM_OC4Init(TIM3, &TIM_OCInitStructure);     //使能通道1

TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);    //使用CCR3寄存器的影子寄存器(直到产生更新事件才发生更改)

//TIM_ARRPreloadConfig(TIM3, ENABLE);            // 使能TIM3重载寄存器ARR

/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);                   //使能定时器3

}

void TIM3_Init(void)
{
//TIM3_NVIC_Configuration();
TIM3_GPIO_Config();
TIM3_Mode_Config();
}

由于本人并不擅长PID,就不粘贴PID了,而且·PID和具体系统有关。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133868.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Android开发:bindService的使用方法

    Android开发:bindService的使用方法http://blog.csdn.net/zhou_wenchong/article/details/51302574bindService用于绑定一个服务。这样当bindService(intent,conn,flags)后,就会绑定一个服务。这样做可以获得这个服务对象本身,而用startService(intent)的方法只能启动服务。   bindService方式的一般过程:

  • 深度学习环境配置2——windows下的torch=1.2.0环境配置「建议收藏」

    深度学习环境配置2——windows下的torch=1.2.0环境配置「建议收藏」神经网络学习小记录48——windows下的torch=1.2.0环境配置学习前言环境内容Anaconda安装下载Cudnn和CUDA配置torch环境安装VSCODE学习前言好多人问环境怎么配置,还是出个教程吧。环境内容torch:1.2.0torchvision:0.4.0Anaconda安装最新版本的Anaconda没有VSCODE,如果大家为了安装VSCODE方便可以直接安装旧版的Anaconda,百度网盘连接如下。也可以装新版然后分开装VSCODE。链接:https://pan

  • MySQL启动和关闭命令

    MySQL启动和关闭命令文章目录一.Windws系统二.Linux系统1.service命令2./etc/init.d/mysql3.mysqld命令4.mysqld_safe命令5.mysqld_multi命令6.mysqladmin命令7.杀进程8.总结备注:测试数据库版本为MySQL8.0这个blog我们来聊聊MySQL的启动和关闭命令一.Windws系统–启动MySQLnetstartmysql–关闭MySQLnetstopmysql二.Linux系统1.service命令–

  • Java创建数组的几种方式[通俗易懂]

    Java创建数组的几种方式[通俗易懂]1、一维数组的声明方式:type[]arrayName;或 typearrayName[]; 附:推荐使用第一种格式,因为第一种格式具有更好的可读性,表示type[]是一种引用类型(数组)而不是type类型。建议不要使用第二种方式下面是典型的声明数组的方式: //声明整型数组 int[]intArray0; intintArray1[]; /

  • VS2008 WEB组件安装失败——解决办法[通俗易懂]

    VS2008 WEB组件安装失败——解决办法[通俗易懂]    最近在安装SqlServer2008R2时意外失败,错误从来没见过,原因无从查起。于是卸载了VisualStudio2008,然后把数据库和VS2008都重新装一遍,谁知道VS2008安装时竟然失败了,提示“WEB组件安装失败”。在网上查了下原因,很多人说的都是废话,结合部分有用的意见,我尝试了如下解决办法:  1、根据提示,是第一个组件“VisualStudioWeb…

  • leetcode-55跳跃游戏[通俗易懂]

    leetcode-55跳跃游戏[通俗易懂]给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标。示例 1:输入:nums = [2,3,1,1,4]输出:true解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。示例 2:输入:nums = [3,2,1,0,4]输出:false解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号