大家好,又见面了,我是你们的朋友全栈君。
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(LDC1314也是TI公司的一个电感传感器、与LDC1000相比、1314功能更加强大,相比ldc1000单通道该传感器含4通道的外部金属检测输入端)。至于小车主要是其它模块的载体和执行部件,控制的时候根据传感器反馈信息作出相应的动作与反应。
一、硬件设计
1、系统总体设计
系统总体框图如图1所示,由电源模块给单片机和L298N驱动供电。单片机读取LDC1000的值和红外测速得到的脉冲,然后把行驶距离和时间显示在液晶屏上,并且对电机进行反馈控制。
2、模块设计
(1)电源模块
考虑到小车是移动电源的电池供电,对功耗的控制在此显得尤为总要。由于开关稳压电源的效率高于一般的线性稳压电源,本系统由开关电源模块用于给单片机提供稳定的电源。主要使用以LM2576adj为电源PWM控制的输出可调降压式电源控制芯片为主的开关电源电路作为单片机的5V恒压输入。电机驱动电路(L298N电机驱动电路)使用电池输出的电压11V作为动力电源输入,减小其中不必要的能量损失。
(2):主控芯片的选择
以STM32F103VET6单片机为核心的控制方式。STM32F103VET6是意法半导体公司生产的一款以ARM cortex-m3为内核的32位微控制器。STM32F103VCT6有512KBFlash,48K的RAM,8个定时器,3个SPI,2个I2C等,片内资源丰富。工作频率可以达到72MHz,可以满足各类控制需求。ST公司的控制芯片尤其是以cortex-M系列的控制芯片已超高的性价比非常适合各种工控领域、本次电赛主要是以STM32F103VET6单片机为本次设计的微控制器。
(3)金属轨道探测模块(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模块测量数据从LDC1000寄存器读出来低八位和高八位,合成为一个有效数值,然后通过计算可以得到等效并联电阻和谐振频率值根据这两个量,可以推知物体离线圈的距离。从第四天开始,我们改用LDC1000——方案有二:
① 用一个线圈,利用PID来判断方向的转变(认识的一位非本校的师兄就是这样实现的),不过难点在于1、线圈要大一点,感应强度要强一些。2、小车要好控制(电机和舵机要好用)。3、PID算法参数要选的非常好才行,不然很容易出轨道。
② 用两个线圈,安置在左和右用来判断方向,加上PID更可以精确一些控制。
由于我们用了直流电机(并没编码电机),其次舵机不怎么样,而且我没有好的大一点的线圈(学校老师打的PCB线圈效果极差!),担心一个线圈调不出来,所以我们采用两个线圈切换办法同样切换装置也是问题(一、用什么切换。二、切换频率对效果的影响。)方案同样有二:1、场管;2、继电器。最终选择了继电器,频率改变小一些(的确•继电器对线圈采集的数据有一定影响,而且电流有一点变化),好在最终也算实现了。
3、电机驱动模块
本次设计使用L298N作为电机驱动。L298N是一种双H桥电机驱动芯片,其中每个H桥可以提供2A的电流,并且配有2个使能端,能够对输出进行控制。功率部分的供电电压范围是2.5-48v,逻辑部分5v供电,接受5vTTL电平。
4、其它模块
其它的相关模块如继电器驱动、1602液晶接口电路等小模块原理就较简单,此处不多赘述。
总结几点:
一:熬夜一定要放慢动作,谨慎做事,很容易因为太困弄坏东西,得不偿失(比赛七天,前五天每天4点睡,八点起,后两天连续通宵)在很累很困的情况很容易弄错的,我们烧了1314和电源板很大原因就是太累太困又心急。
二:继电器驱动使用灌电流,不能使用拉电流(一开始怎么都驱动不了继电器,就连2003都不行,也是想不通,后来查资料找到了,卡了半天时间)
三:PID参数一定对应一个系统,系统变则参数变、参数调节时应该注意参数调节的顺序和调节次序。一般遵循顺序:
a.确定比例增益 P
确定比例增益 P 时,首先去掉 PID 的积分项和微分项, 一般是令 Ti=0、 Td=0,
PID 为纯比例调节。输入设定为系统允许的最大值的 60%~70%,由 0 逐渐加大比
例增益 P,直至系统出现振荡;再反过来,从此时的比例增益 P 逐渐减小,直至
系统振荡消失,记录此时的比例增益 P,设定 PID 的比例增益 P 为当前值的
60%~70%。比例增益 P 调试完成。
b.确定积分时间常数 Ti
比例增益 P 确定后,设定一个较大的积分时间常数 Ti 的初值,然后逐渐减
小 Ti,直至系统出现振荡,之后在反过来,逐渐加大 Ti,直至系统振荡消失。
记录此时的 Ti,设定 PID 的积分时间常数 Ti 为当前值的 150%~180%。积分时间
常数 Ti 调试完成。
c.确定积分时间常数 Td
比例增益 P 确定后,设定一个较大的积分时间常数 Ti 的初值,然后逐渐减
小 Ti,直至系统出现振荡,之后在反过来,逐渐加大 Ti,直至系统振荡消失。
记录此时的 Ti,设定 PID 的积分时间常数 Ti 为当前值的 150%~180%。积分时间
常数 Ti 调试完成。
四:使用SPI3的同时不能使用JTAG的复用时钟,需要关闭其复用时钟(具体我再研究研究,比赛当时使用SPI3一开始不顺利,关闭JTAG的复用时钟就ok了)
五:LDC1314和LDC1000的芯片可以改变检测的数值范围,调大差距值,但是我认为并不能改变灵敏度,而是通过调节线圈电感和连接的电容来改变灵敏度(具体可以见TI官网的在线计算工具)
六:选用PID算法的时候,反馈一定要可靠,即选用的传感器反馈数据一定要准或则传感器一定要调准确。
最后就是一点遗憾了:第一、觉得自己准备不足,很多东西应该自己准备好的,尤其是小车,我很后悔用了一个性能太差的,直流电机(两边轮子相同电压转速还明显不一样),舵机小角度比较差,要么不转,要么转大角度。其他就是线圈我很后悔没有自己打,学校打那个确实太差,有些根本就检测不大。第二、后悔放弃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();
}
include “pid.h”
include “sys.h”
include “motor.h”
include “delay.h”
extern unsigned long ProximityData,red_ProximityData,bule_ProximityData;
extern unsigned long jichu_red,jichu_bule;
extern u16 CCR3_Val,CCR4_Val;
void pid_pwm_red()//
{
int chazhi_z = 0, pid_val_z = 0, weifen_z=0;
// float pid_p_z = 1.05,pid_i_z = 0.1, pid_d_z = 2.5;
static int jifen_z = 0, l_chazhi_z= 0, l_val_z= 0;
float pid_p_z = 1.8,pid_i_z = 0, pid_d_z = 0;
chazhi_z = red_ProximityData – jichu_red;
jifen_z += chazhi_z;
if(jifen_z> 400)
{
jifen_z= 400;
}
else if(jifen_z < -400)
{
jifen_z = -400;
}
weifen_z = chazhi_z – l_chazhi_z;
if(weifen_z > 10)
{
weifen_z = 10;
}
if(weifen_z < -10)
{
weifen_z = -10;
}
pid_val_z = chazhi_z*pid_p_z+jifen_z*pid_i_z+weifen_z*pid_d_z;
if(pid_val_z>0)
{
TIM_SetCompare3(TIM5, CCR3_Val+pid_val_z);
TIM_SetCompare4(TIM5, CCR4_Val-pid_val_z);
}
else
{
TIM_SetCompare3(TIM5, CCR3_Val-pid_val_z);
TIM_SetCompare4(TIM5, CCR4_Val+pid_val_z);
}
l_chazhi_z = chazhi_z;
}
void pid_pwm_blue(void)
{
int chazhi_y = 0, pid_val_y = 0, weifen_y=0;
// float pid_p_y = 1.9, pid_i_y = 1, pid_d_y = 3;
static int jifen_y = 0, l_chazhi_y= 0, l_val_= 0;
float pid_p_y = 1.2, pid_i_y = 0.1, pid_d_y =0.05; //1.5 0.05
chazhi_y = bule_ProximityData-jichu_bule;
jifen_y+= chazhi_y;
if(jifen_y> 200)
{
jifen_y= 200;
}
else if(jifen_y < -200)
{
jifen_y = -200;
}
weifen_y = chazhi_y – l_chazhi_y;
if(weifen_y > 10)
{
weifen_y = 10;
}
if(weifen_y < -10)
{
weifen_y = -10;
}
pid_val_y = chazhi_y*pid_p_y+jifen_y*pid_i_y+weifen_y*pid_d_y;
if(pid_val_y>0)
{
TIM_SetCompare3(TIM5, CCR3_Val-pid_val_y);
TIM_SetCompare4(TIM5, CCR4_Val+pid_val_y);
}
else
{
TIM_SetCompare3(TIM5, CCR3_Val+pid_val_y);
TIM_SetCompare4(TIM5, CCR4_Val+pid_val_y);
}
l_chazhi_y = chazhi_y;
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133967.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...