加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入

第八章-PID 速度控制 PID控制 PID調(diào)參 PID溫度控制 藍(lán)橋杯 串級(jí)PID 模糊PID

06/19 10:29
2722
服務(wù)支持:
技術(shù)交流群

完成交易后在“購(gòu)買成功”頁(yè)面掃碼入群,即可與技術(shù)大咖們分享疑惑和經(jīng)驗(yàn)、收獲成長(zhǎng)和認(rèn)同、領(lǐng)取優(yōu)惠和紅包等。

虛擬商品不可退

當(dāng)前內(nèi)容為數(shù)字版權(quán)作品,購(gòu)買后不支持退換且無(wú)法轉(zhuǎn)移使用。

加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論
放大
實(shí)物圖
相關(guān)方案
  • 方案介紹
    • 第八章-PID-速度控制
  • 相關(guān)文件
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

第八章-PID-速度控制

8.1-速度控制探索

前面我們已經(jīng)能夠通過(guò)編碼器測(cè)量出速度值,下面我們來(lái)控制速度

我們先編寫一個(gè)簡(jiǎn)單的控制方法

要求:講轉(zhuǎn)速控制再2.9-3.1轉(zhuǎn)每秒

可以把中斷里面不重要的輸出注釋掉
在這里插入圖片描述

	if(Motor1Speed>3.1) Motor1Pwm--;
	if(Motor1Speed<2.9) Motor1Pwm++;
	if(Motor2Speed>3.1) Motor2Pwm--;
	if(Motor2Speed<2.9) Motor2Pwm++;
	Motor_Set(Motor1Pwm,Motor2Pwm);
	printf("Motor1Speed:%.2f Motor1Pwm:%drn",Motor1Speed,Motor1Pwm);
	printf("Motor2Speed:%.2f Motor2Pwm:%drn",Motor2Speed,Motor2Pwm);
	
	HAL_Delay(100);

開(kāi)始實(shí)驗(yàn)
在這里插入圖片描述
現(xiàn)象就開(kāi)始電機(jī)沒(méi)有到達(dá)3轉(zhuǎn)每秒,PWM占空比逐漸增大,電機(jī)逐漸達(dá)到要求轉(zhuǎn)速、到達(dá)要求轉(zhuǎn)速后我們?cè)黾幼枇?,電機(jī)變慢,阻力大小不邊PWM占空比逐漸更大轉(zhuǎn)速逐漸更大。

這樣我們就把轉(zhuǎn)速控制到我們想要的范圍,但是我們并不滿意、能夠看出來(lái)控制的速度很慢,給電機(jī)一些阻力電機(jī)至少要2-3秒能夠調(diào)整過(guò)來(lái),這在一些場(chǎng)景是不允許的。

我們理想的控制效果是:在電機(jī)轉(zhuǎn)速很慢的是時(shí)候能快速調(diào)整,在電機(jī)一直轉(zhuǎn)的不能達(dá)到要求時(shí)候能夠更快速度調(diào)整

8.2-準(zhǔn)備工作-匿名上位機(jī)曲線顯示速度波形方便觀察數(shù)據(jù)

為了方便觀察電機(jī)速度數(shù)據(jù),我們通過(guò)上位機(jī)曲線顯示一下。

這里我們使用的上位機(jī)是匿名上位機(jī)-大佬寫的非常穩(wěn)定功能也很多

我使用的版本是:匿名上位機(jī)V7.2.2.8版本推薦大家和我使用一樣
匿名上位機(jī)官方下載鏈接:https://www.anotc.com/wiki/匿名產(chǎn)品資料/資料下載鏈接匯總

在這里插入圖片描述
我們要把STM32數(shù)據(jù)發(fā)送到匿名上位機(jī),就要滿足匿名上位機(jī)的數(shù)據(jù)協(xié)議要求

在匿名上位機(jī)資料下載鏈接,可以下載到協(xié)議介紹

  • 匿名上位機(jī)V7通信協(xié)議,20210528發(fā)布:https://pan.baidu.com/s/1nGrIGWj6qr9DWOcGpKR51g 提取碼:z8d1
  • CSDN 慕羽★大佬寫的協(xié)議解析教程博客:https://blog.csdn.net/qq_44339029/article/details/106004997
    1.先補(bǔ)充一下大小端模式
    這是因?yàn)樵?a class="article-link" target="_blank" href="/tag/%E8%AE%A1%E7%AE%97%E6%9C%BA/">計(jì)算機(jī)系統(tǒng)中,我們是以字節(jié)為單位的,每個(gè)地址單元都對(duì)應(yīng)著一個(gè)字節(jié),一個(gè)字節(jié)為 8bit。但是在C語(yǔ)言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對(duì)于位數(shù)大于8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于一個(gè)字節(jié),那么必然存在著一個(gè)如和將多個(gè)字節(jié)安排的問(wèn)題。因此就導(dǎo)致了大端存儲(chǔ)模式和小端存儲(chǔ)模式。例如一個(gè)16bit的short型x,在內(nèi)存中的地址為0x0010,x的值為0x1122,那么0x11為高字節(jié),0x22為低字節(jié)。對(duì)于大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。
  • 所謂的大端模式(BE big-endian),是指數(shù)據(jù)的低位保存在內(nèi)存的高地址中,而數(shù)據(jù)的高位,保存在內(nèi)存的低地址中(低對(duì)高,高對(duì)低);
  • 所謂的小端模式(LE little-endian),是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,而數(shù)據(jù)的高位保存在內(nèi)存的高地址中(低對(duì)低,高對(duì)高)。
    常見(jiàn)的單片機(jī)大小端模式:(1)KEIL C51中,變量都是大端模式的,而KEIL MDK中,變量是小端模式的。(2)SDCC-C51是小端尋址,AVRGCC 小端尋址.(3)PC小端,大部分ARM是小端 (4)總起來(lái)說(shuō)51單片機(jī)一般是大端模式,32單片機(jī)一般是小端模式.
    在這里插入圖片描述
    2.看一下上位機(jī)要求的協(xié)議
    在這里插入圖片描述
    靈活格式幀(用戶自定義幀)
    在這里插入圖片描述
    前面我們好理解

0xAA:一個(gè)字節(jié)表示開(kāi)始

0xFF:一個(gè)字節(jié)表示目標(biāo)地址

0xF1:一個(gè)字節(jié)表示發(fā)送功能碼

1-40:一個(gè)字節(jié)表示數(shù)據(jù)長(zhǎng)度

數(shù)據(jù)內(nèi)容有多個(gè)字節(jié)如何發(fā)送

因?yàn)榇诿看伟l(fā)送一個(gè)字節(jié),但是數(shù)據(jù)可能是int16_t 16位的數(shù)據(jù),或者int32_t 32位數(shù)據(jù),每次發(fā)送16位數(shù)據(jù),先發(fā)送數(shù)據(jù)低八位,還是先發(fā)送數(shù)據(jù)高八位那?

匿名協(xié)議通信介紹給出:DATA 數(shù)據(jù)內(nèi)容中的數(shù)據(jù),采用小端模式傳送,低字節(jié)在前,高字節(jié)在后。

那么就要求,比如我們?cè)诎l(fā)送16位數(shù)據(jù)0x2314我們要先發(fā)送低字節(jié)0x14,然后發(fā)送高字節(jié)0x23

那么如何解析出低字節(jié)或者高字節(jié),就需要知道多字節(jié)數(shù)據(jù)在單片機(jī)里面是怎么存的,因?yàn)镾TM32是小端存儲(chǔ),所以低字節(jié)就在低位地址中,高字節(jié)高位地址中。

如果使用32單片機(jī) 小端模式,0x23高地址,0x14在低地址,所以我們要先發(fā)低地址,再發(fā)高地址。

下面就是對(duì)16位數(shù)據(jù),或者32位數(shù)據(jù)的拆分

//需要發(fā)送16位,32位數(shù)據(jù),對(duì)數(shù)據(jù)拆分,之后每次發(fā)送單個(gè)字節(jié)
//拆分過(guò)程:對(duì)變量dwTemp 去地址然后將其轉(zhuǎn)化成char類型指針,最后再取出指針?biāo)赶虻膬?nèi)容
#define BYTE0(dwTemp)  (*(char *)(&dwTemp))
#define BYTE1(dwTemp)  (*((char *)(&dwTemp) + 1))
#define BYTE2(dwTemp)  (*((char *)(&dwTemp) + 2))
#define BYTE3(dwTemp)  (*((char *)(&dwTemp) + 3))

拆分后我們按照協(xié)議要求發(fā)送數(shù)據(jù)就可以了
在這里插入圖片描述
niming.c

#include "niming.h"
#include "main.h"
#include "usart.h"
uint8_t data_to_send[100];

//通過(guò)F1幀發(fā)送4個(gè)uint16類型的數(shù)據(jù)
void ANO_DT_Send_F1(uint16_t _a, uint16_t _b, uint16_t _c, uint16_t _d)
{
    uint8_t _cnt = 0;		//計(jì)數(shù)值
    uint8_t sumcheck = 0;  //和校驗(yàn)
    uint8_t addcheck = 0; //附加和校驗(yàn)
    uint8_t i = 0;
	data_to_send[_cnt++] = 0xAA;//幀頭
    data_to_send[_cnt++] = 0xFF;//目標(biāo)地址
    data_to_send[_cnt++] = 0xF1;//功能碼
    data_to_send[_cnt++] = 8; //數(shù)據(jù)長(zhǎng)度
	//單片機(jī)為小端模式-低地址存放低位數(shù)據(jù),匿名上位機(jī)要求先發(fā)低位數(shù)據(jù),所以先發(fā)低地址
	data_to_send[_cnt++] = BYTE0(_a);       
    data_to_send[_cnt++] = BYTE1(_a);
	
    data_to_send[_cnt++] = BYTE0(_b);
    data_to_send[_cnt++] = BYTE1(_b);
	
    data_to_send[_cnt++] = BYTE0(_c);
    data_to_send[_cnt++] = BYTE1(_c);
	
    data_to_send[_cnt++] = BYTE0(_d);
    data_to_send[_cnt++] = BYTE1(_d);
	 for ( i = 0; i < data_to_send[3]+4; i++)
    {
        sumcheck += data_to_send[i];//和校驗(yàn)
        addcheck += sumcheck;//附加校驗(yàn)
    }
    data_to_send[_cnt++] = sumcheck;
    data_to_send[_cnt++] = addcheck;
	HAL_UART_Transmit(&huart1,data_to_send,_cnt,0xFFFF);//這里是串口發(fā)送函數(shù)
}
//,通過(guò)F2幀發(fā)送4個(gè)int16類型的數(shù)據(jù)
void ANO_DT_Send_F2(int16_t _a, int16_t _b, int16_t _c, int16_t _d)   //F2幀  4個(gè)  int16 參數(shù)
{
    uint8_t _cnt = 0;
    uint8_t sumcheck = 0; //和校驗(yàn)
    uint8_t addcheck = 0; //附加和校驗(yàn)
    uint8_t i=0;
   data_to_send[_cnt++] = 0xAA;
    data_to_send[_cnt++] = 0xFF;
    data_to_send[_cnt++] = 0xF2;
    data_to_send[_cnt++] = 8; //數(shù)據(jù)長(zhǎng)度
	//單片機(jī)為小端模式-低地址存放低位數(shù)據(jù),匿名上位機(jī)要求先發(fā)低位數(shù)據(jù),所以先發(fā)低地址
    data_to_send[_cnt++] = BYTE0(_a);
    data_to_send[_cnt++] = BYTE1(_a);
	
    data_to_send[_cnt++] = BYTE0(_b);
    data_to_send[_cnt++] = BYTE1(_b);
	
    data_to_send[_cnt++] = BYTE0(_c);
    data_to_send[_cnt++] = BYTE1(_c);
	
    data_to_send[_cnt++] = BYTE0(_d);
    data_to_send[_cnt++] = BYTE1(_d);
	
	  for ( i = 0; i < data_to_send[3]+4; i++)
    {
        sumcheck += data_to_send[i];
        addcheck += sumcheck;
    }

    data_to_send[_cnt++] = sumcheck;
    data_to_send[_cnt++] = addcheck;
	
	HAL_UART_Transmit(&huart1,data_to_send,_cnt,0xFFFF);//這里是串口發(fā)送函數(shù)
}
//通過(guò)F3幀發(fā)送2個(gè)int16類型和1個(gè)int32類型的數(shù)據(jù)
void ANO_DT_Send_F3(int16_t _a, int16_t _b, int32_t _c )   //F3幀  2個(gè)  int16 參數(shù)   1個(gè)  int32  參數(shù)
{
    uint8_t _cnt = 0;
    uint8_t sumcheck = 0; //和校驗(yàn)
    uint8_t addcheck = 0; //附加和校驗(yàn)
    uint8_t i=0;
    data_to_send[_cnt++] = 0xAA;
    data_to_send[_cnt++] = 0xFF;
    data_to_send[_cnt++] = 0xF3;
    data_to_send[_cnt++] = 8; //數(shù)據(jù)長(zhǎng)度
	//單片機(jī)為小端模式-低地址存放低位數(shù)據(jù),匿名上位機(jī)要求先發(fā)低位數(shù)據(jù),所以先發(fā)低地址
    data_to_send[_cnt++] = BYTE0(_a);
    data_to_send[_cnt++] = BYTE1(_a);
	
    data_to_send[_cnt++] = BYTE0(_b);
    data_to_send[_cnt++] = BYTE1(_b);
	
    data_to_send[_cnt++] = BYTE0(_c);
    data_to_send[_cnt++] = BYTE1(_c);
    data_to_send[_cnt++] = BYTE2(_c);
    data_to_send[_cnt++] = BYTE3(_c);
	
	  for ( i = 0; i < data_to_send[3]+4; i++)
    {
        sumcheck += data_to_send[i];
        addcheck += sumcheck;
    }

    data_to_send[_cnt++] = sumcheck;
    data_to_send[_cnt++] = addcheck;

	HAL_UART_Transmit(&huart1,data_to_send,_cnt,0xFFFF);//這里是串口發(fā)送函數(shù)
}

niming.h

#ifndef  NIMING_H
#define  NIMING_H
#include "main.h"
//需要發(fā)送16位,32位數(shù)據(jù),對(duì)數(shù)據(jù)拆分,之后每次發(fā)送單個(gè)字節(jié)
//拆分過(guò)程:對(duì)變量dwTemp 去地址然后將其轉(zhuǎn)化成char類型指針,最后再取出指針?biāo)赶虻膬?nèi)容
#define BYTE0(dwTemp)  (*(char *)(&dwTemp))
#define BYTE1(dwTemp)  (*((char *)(&dwTemp) + 1))
#define BYTE2(dwTemp)  (*((char *)(&dwTemp) + 2))
#define BYTE3(dwTemp)  (*((char *)(&dwTemp) + 3))


void ANO_DT_Send_F1(uint16_t, uint16_t _b, uint16_t _c, uint16_t _d);
void ANO_DT_Send_F2(int16_t _a, int16_t _b, int16_t _c, int16_t _d);
void ANO_DT_Send_F3(int16_t _a, int16_t _b, int32_t _c );

#endif 

添加測(cè)試代碼
在這里插入圖片描述

	//電機(jī)速度等信息發(fā)送到上位機(jī)
	//注意上位機(jī)不支持浮點(diǎn)數(shù),所以要乘100
	ANO_DT_Send_F2(Motor1Speed*100, 3.0*100,Motor2Speed*100,3.0*100);

下面設(shè)置上位機(jī)-數(shù)據(jù)解析
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
這個(gè)是控制效果,并不理想,后面我們介紹PID控制
在這里插入圖片描述

8.3-P I D 逐個(gè)參數(shù)理解

在這里插入圖片描述
加入的現(xiàn)在 過(guò)去 未來(lái)概念

p:現(xiàn)在

i:過(guò)去

d:未來(lái)
在這里插入圖片描述
那么我們就開(kāi)始寫PID

PID的結(jié)構(gòu)體類型變量、里面成員都是浮點(diǎn)類型

先在pid.h聲明一個(gè)結(jié)構(gòu)體類型、聲明.c中的函數(shù)
在這里插入圖片描述

#ifndef __PID_H
#define __PID_H

//聲明一個(gè)結(jié)構(gòu)體類型
typedef struct 
{
	float target_val;//目標(biāo)值
	float actual_val;//實(shí)際值
	float err;//當(dāng)前偏差
	float err_last;//上次偏差
	float err_sum;//誤差累計(jì)值
	float Kp,Ki,Kd;//比例,積分,微分系數(shù)
	
} tPid;

//聲明函數(shù)
float P_realize(tPid * pid,float actual_val);
void PID_init(void);
float PI_realize(tPid * pid,float actual_val);
float PID_realize(tPid * pid,float actual_val);
#endif

然后在pid.c中定義結(jié)構(gòu)體類型變量
在這里插入圖片描述

#include "pid.h"

//定義一個(gè)結(jié)構(gòu)體類型變量
tPid pidMotor1Speed;
//給結(jié)構(gòu)體類型變量賦初值
void PID_init()
{
	pidMotor1Speed.actual_val=0.0;
	pidMotor1Speed.target_val=0.00;
	pidMotor1Speed.err=0.0;
	pidMotor1Speed.err_last=0.0;
	pidMotor1Speed.err_sum=0.0;
	pidMotor1Speed.Kp=0;
	pidMotor1Speed.Ki=0;
	pidMotor1Speed.Kd=0;
}
//比例p調(diào)節(jié)控制函數(shù)
float P_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//傳遞真實(shí)值
	pid->err = pid->target_val - pid->actual_val;//當(dāng)前誤差=目標(biāo)值-真實(shí)值
	//比例控制調(diào)節(jié)   輸出=Kp*當(dāng)前誤差
	pid->actual_val = pid->Kp*pid->err;
	return pid->actual_val;
}
//比例P 積分I 控制函數(shù)
float PI_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//傳遞真實(shí)值
	pid->err = pid->target_val - pid->actual_val;//當(dāng)前誤差=目標(biāo)值-真實(shí)值
	pid->err_sum += pid->err;//誤差累計(jì)值 = 當(dāng)前誤差累計(jì)和
	//使用PI控制 輸出=Kp*當(dāng)前誤差+Ki*誤差累計(jì)值
	pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum;
	
	return pid->actual_val;
}
// PID控制函數(shù)
float PID_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//傳遞真實(shí)值
	pid->err = pid->target_val - pid->actual_val;當(dāng)前誤差=目標(biāo)值-真實(shí)值
	pid->err_sum += pid->err;//誤差累計(jì)值 = 當(dāng)前誤差累計(jì)和
	//使用PID控制 輸出 = Kp*當(dāng)前誤差  +  Ki*誤差累計(jì)值 + Kd*(當(dāng)前誤差-上次誤差)
	pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum + pid->Kd*(pid->err - pid->err_last);
	//保存上次誤差: 這次誤差賦值給上次誤差
	pid->err_last = pid->err;
	
	return pid->actual_val;
}

然后在main中要調(diào)用PID_init();函數(shù)
在這里插入圖片描述

  PID_init();

p調(diào)節(jié)函數(shù)函數(shù)只根據(jù)當(dāng)前誤差進(jìn)行控制

//比例p調(diào)節(jié)控制函數(shù)
float P_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//傳遞真實(shí)值
	pid->err = pid->target_val - pid->actual_val;//目標(biāo)值減去實(shí)際值等于誤差值
	//比例控制調(diào)節(jié)
	pid->actual_val = pid->Kp*pid->err;
	return pid->actual_val;
}

主函數(shù)-可以估算當(dāng)p=10 就有較好的響應(yīng)速度

先看根據(jù)p比例控制的效果
在這里插入圖片描述
p調(diào)節(jié) 電機(jī)穩(wěn)態(tài)后還是存在誤差。

下面加入i 調(diào)節(jié)也就是加入歷史誤差
pi的控制函數(shù)

//比例P 積分I 控制函數(shù)
float PI_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//傳遞真實(shí)值
	pid->err = pid->target_val - pid->actual_val;//目標(biāo)值減去實(shí)際值等于誤差值
	pid->err_sum += pid->err;//誤差累計(jì)求和
	//使用PI控制
	pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum;
	
	return pid->actual_val;
}

因?yàn)閷?shí)際值1.6的時(shí)候誤差為1.4 上次偏差1.4和這次偏差1.4相加2.8 我們乘5 等于10點(diǎn)多就會(huì)有較好控制效果
這是pi 調(diào)節(jié)的控制效果
在這里插入圖片描述
下面是PID調(diào)節(jié)的

// PID控制函數(shù)
float PID_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//傳遞真實(shí)值
	pid->err = pid->target_val - pid->actual_val;//目標(biāo)值減去實(shí)際值等于誤差值
	pid->err_sum += pid->err;//誤差累計(jì)求和
	//使用PID控制
	pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum + pid->Kd*(pid->err - pid->err_last);
	//保存上次誤差:最近一次 賦值給上次
	pid->err_last = pid->err;
	
	return pid->actual_val;
}

8.4-加入cJSON方便上位機(jī)調(diào)參

在這里插入圖片描述
調(diào)大堆棧
在這里插入圖片描述
軟件開(kāi)啟中斷
在這里插入圖片描述
開(kāi)啟接收中斷
在這里插入圖片描述

 __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);	//開(kāi)啟串口1接收中斷

中斷回調(diào)函數(shù)

在這里插入圖片描述

uint8_t Usart1_ReadBuf[256];	//串口1 緩沖數(shù)組
uint8_t Usart1_ReadCount = 0;	//串口1 接收字節(jié)計(jì)數(shù)
  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE))//判斷huart1 是否讀到字節(jié)
  {
		if(Usart1_ReadCount >= 255) Usart1_ReadCount = 0;
		HAL_UART_Receive(&huart1,&Usart1_ReadBuf[Usart1_ReadCount++],1,1000);
  }

編寫函數(shù)用于判斷串口是否發(fā)送完一幀數(shù)據(jù)
在這里插入圖片描述

extern uint8_t Usart1_ReadBuf[255];	//串口1 緩沖數(shù)組
extern uint8_t Usart1_ReadCount;	//串口1 接收字節(jié)計(jì)數(shù)

//判斷否接收完一幀數(shù)據(jù)
uint8_t Usart_WaitReasFinish(void)
{
	static uint16_t Usart_LastReadCount = 0;//記錄上次的計(jì)數(shù)值
	if(Usart1_ReadCount == 0)
	{
		Usart_LastReadCount = 0;
		return 1;//表示沒(méi)有在接收數(shù)據(jù)
	}
	if(Usart1_ReadCount == Usart_LastReadCount)//如果這次計(jì)數(shù)值等于上次計(jì)數(shù)值
	{
		Usart1_ReadCount = 0;
		Usart_LastReadCount = 0;
		return 0;//已經(jīng)接收完成了
	}
	Usart_LastReadCount = Usart1_ReadCount;
	return 2;//表示正在接受中
}

然后我們把cJSON庫(kù)放入工程里面

下載cJSON新版

gtihub鏈接:https://github.com/DaveGamble/cJSON

百度網(wǎng)盤鏈接:https://pan.baidu.com/s/1AcNHtZuv5bokMQ2f6QoG7Q

提取碼:a422

和添加其他文件一樣,加入工程,然后指定路徑

編寫解析指令的函數(shù)

在這里插入圖片描述

#include "cJSON.h"
#include <string.h>
   cJSON *cJsonData ,*cJsonVlaue;

	if(Usart_WaitReasFinish() == 0)//是否接收完畢
	{
		cJsonData  = cJSON_Parse((const char *)Usart1_ReadBuf);
		if(cJSON_GetObjectItem(cJsonData,"p") !=NULL)
		{
			cJsonVlaue = cJSON_GetObjectItem(cJsonData,"p");	
		    p = cJsonVlaue->valuedouble;
			pidMotor1Speed.Kp = p;
		}
		if(cJSON_GetObjectItem(cJsonData,"i") !=NULL)
		{
			cJsonVlaue = cJSON_GetObjectItem(cJsonData,"i");	
		    i = cJsonVlaue->valuedouble;
			pidMotor1Speed.Ki = i;
		}
		if(cJSON_GetObjectItem(cJsonData,"d") !=NULL)
		{
			cJsonVlaue = cJSON_GetObjectItem(cJsonData,"d");	
		    d = cJsonVlaue->valuedouble;
			pidMotor1Speed.Kd = d;
		}
		if(cJSON_GetObjectItem(cJsonData,"a") !=NULL)
		{
		
			cJsonVlaue = cJSON_GetObjectItem(cJsonData,"a");	
		    a = cJsonVlaue->valuedouble;
			pidMotor1Speed.target_val =a;
		}
		if(cJsonData != NULL){
		  cJSON_Delete(cJsonData);//釋放空間、但是不能刪除cJsonVlaue不然會(huì) 出現(xiàn)異常錯(cuò)誤
		}
		memset(Usart1_ReadBuf,0,255);//清空接收buf,注意這里不能使用strlen	
	}
	printf("P:%.3f  I:%.3f  D:%.3f A:%.3frn",p,i,d,a);

測(cè)試發(fā)送cJSON數(shù)據(jù)就會(huì)解析收到數(shù)據(jù)
在這里插入圖片描述
然后我們賦值改變一個(gè)電機(jī)的PID參數(shù)和目標(biāo)轉(zhuǎn)速
然后我們通過(guò)串口發(fā)送命令,就會(huì)改變PID的參數(shù)了
這么我們的第八章就弄好了,下篇我們進(jìn)行第九章-PID整定

聯(lián)系:Q,1930299709

  • 聯(lián)系方式.txt

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
CC430F5137IRGZ 1 Texas Instruments 16-Bit ultra-low-power CC430 Sub 1 GHz wireless MCU with 12-Bit ADC, 32kB Flash and 4kB RAM 48-VQFN -40 to 85

ECAD模型

下載ECAD模型
$7.53 查看
S29AL016J70TFI020 1 Cypress Semiconductor Flash, 1MX16, 70ns, PDSO48, TSOP-48
$10.3 查看
LAN8720AI-CP-ABC 1 Microchip Technology Inc Ethernet Transceiver

ECAD模型

下載ECAD模型
$1.26 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜