當前位置:編程學習大全網 - 源碼下載 - 單片機控制風扇調速 具體點最好有源碼就好

單片機控制風扇調速 具體點最好有源碼就好

#include <iom16v.h>

#include <macros.h>

#define OVER_TEMPERATURE 0x01

#define LOW_LIGHT 0X02

#define HIGH_LIGHT 0X03

#define THIS_NODE 0x12

#define CENTRAL_SITE 0x18

#define LIGHT_NODE 0x11

#define OBJ 90

/*#define KP 15

#define KI 1

#define KD 20

#define P (KP + KI + KD)

#define I (KP + 2 * KD)

#define D KD*/

typedef unsigned char uchar;

typedef unsigned int uint;

uint KP = 5;

uchar dKP = 1;

uint KI = 1;

uchar dKI = 2;

uint KD = 3;

uchar dKD = 1;

uchar table[10] = {0xf3, 0x50, 0xcb, 0xd9, 0x78, 0xb9, 0xbb, 0xd0, 0xfb, 0xf9};

uchar node[7] = {0x00, 0x0d, 0x6f, 0x00, 0x0c, 0x08, 0x09};

uchar rcv_buf[4] = {0, 0, 0, 0};

uchar command = 0;

uchar uart_flag = 0;

uchar sec = 0;

uchar minute = 0;

uchar hour = 0;

uchar wakeup = 1;

uchar key_down[4] = {0, 0, 0, 0};

uchar key_up[4] = {0, 0, 0, 0};

uchar pre_key = 0;

uchar cur_key = 0;

uchar key_chg = 0;

uchar time_chg = 0;

uchar key_timer = 0;

uchar uart_isr = 0;

typedef struct _PID{

uint set_point;

uint B;

int ek[3];

int ek_flag[3];

uint uk;

}PID;

PID sPID;

int abs(int num)

{

return ((num>0)?(num):(-num));

}

int delta_PID(PID *pp, int next_point)//增量法

{

int error;

error = pp->set_point - next_point;

pp->ek[2] = pp->ek[1];

pp->ek[1] = pp->ek[0];

pp->ek[0] = error;

return (KP*pp->ek[0] - KI*pp->ek[1] + KD*pp->ek[2]);

}

void PIDproc(PID *pp, int next_point) //帶死區控制以及抗積分飽和的PID

{

uint tmp[3] = {0, 0, 0};

uint PosSum = 0;

uint NegSum = 0;

uchar gain = 1;

if(pp->set_point > next_point){

tmp[0] = pp->set_point - next_point;//ek0

if(tmp[0] > pp->B){

pp->ek[2] = pp->ek[1];

pp->ek[1] = pp->ek[0];

pp->ek[0] = tmp[0];

pp->ek_flag[2] = pp->ek_flag[1];

pp->ek_flag[1] = pp->ek_flag[0];

pp->ek_flag[0] = 0; //當前EK為正數

tmp[0] = KP * pp->ek[0] / dKP + KI * pp->ek[0] / dKI + KD * pp->ek[0] / dKD; // KP*EK0

tmp[1] = KP * pp->ek[1] / dKP + 2 * KD * pp->ek[1] / dKD; // KI*EK1

tmp[2] = KD * pp->ek[2] / dKD; // KD*EK2

}

}

else{ //反饋大於給定

tmp[0] = next_point - pp->set_point;//ek0

if(tmp[0] > pp->B){

//數值移位

pp->ek[2] = pp->ek[1];

pp->ek[1] = pp->ek[0];

pp->ek[0] = tmp[0];

//符號移位

pp->ek_flag[2] = pp->ek_flag[1];

pp->ek_flag[1] = pp->ek_flag[0];

pp->ek_flag[0] = 1; //當前EK為負數

tmp[0] = KP * pp->ek[0] / dKP + KI * pp->ek[0] / dKI + KD * pp->ek[0] / dKD; // KP*EK0

tmp[1] = KP * pp->ek[1] / dKP + 2 * KD * pp->ek[1] / dKD; // KI*EK1

tmp[2] = KD * pp->ek[2] / dKD; // KD*EK2

}

}

/*以下部分代碼是講所有的正數項疊加,負數項疊加*/

if(pp->ek_flag[0]==0){

PosSum += tmp[0]; //正數和

}

else{

NegSum += tmp[0]; //負數和

} // KP*EK0

if(pp->ek_flag[1]!=0){

PosSum += tmp[1]; //正數和

}

else{

NegSum += tmp[1]; //負數和

} // - kI * EK1

if(pp->ek_flag[2]==0){

PosSum += tmp[2]; //正數和

}

else{

NegSum += tmp[2]; //負數和

} // KD * EK2

PosSum += pp->uk; //

if(PosSum > NegSum){ // 是否控制量為正數

tmp[0] = PosSum - NegSum;

tmp[0] *= gain;

if( tmp[0] < (uint)65000){ //小於限幅值則為計算值輸出

pp->uk = tmp[0];

}

else{

pp->uk = (uint)65000; //否則為限幅值輸出

}

}

else{ //控制量輸出為負數,則輸出0

pp->uk = 0;

}

}

void PID_init(PID* pp)

{

pp->set_point = OBJ;

pp->B = 0;

pp->ek[0] = 0;

pp->ek[1] = 0;

pp->ek[2] = 0;

pp->ek_flag[0] = 0;

pp->ek_flag[1] = 0;

pp->ek_flag[2] = 0;

pp->uk = 0;

}

void delay(int n)

{

int i = 0, j = 0;

for(i = 0; i < n; i++)

for(j = 0; j < 1000; j++);

}

void disp(int a)

{

uchar flag = 0;

PORTC = 0X01;

PORTB = table[a / 1000];

delay(3);

PORTB = 0X00;

PORTC = 0X02;

PORTB = table[a / 100 % 10];

delay(3);

PORTB = 0X00;

PORTC = 0X04;

PORTB = table[a / 10 % 10];

delay(3);

PORTB = 0X00;

PORTC = 0X08;

PORTB = table[a % 10];

delay(3);

PORTB = 0X00;

}

void delay_on(int n, uchar cur_val)

{

int i = 0, j = 0;

for(i = 0; i < n; i++)

for(j = 0; j < 30; j++)

disp(cur_val);

}

void uart0_init(void)

{

UCSRB = 0x00; //disable while setting baud rate

UCSRA = 0x00;

UCSRC = 0x06;//BIT(URSEL) | 0x06;

UBRRL = 0x0b; //set baud rate lo 0x03:115.2k,0x17:19200,0x0b:38400

UBRRH = 0x00; //set baud rate hi

UCSRB = 0x98;

}

// 數據發送發送5 到8 位數據位的幀

void USART_Transmit( unsigned char data )

{

while ( !( UCSRA & (1<<UDRE)));

UDR = data;

}

// 數據接收以5 到8 個數據位的方式接收數 據幀

unsigned char USART_Receive( void )

{

while (!(UCSRA & (1<<RXC)));

return UDR;

}

void USART_TranStr(uchar data[], uchar n)

{

uchar i = 0;

for(i = 0; i < n; i++)

{

USART_Transmit(data[i]);

}

}

#pragma interrupt_handler uart_rx_isr:iv_USART_RX

void uart_rx_isr(void)

{

uchar i;

for(i = 0; i < 4; i++)

{

rcv_buf[i] = USART_Receive();

}

uart_flag = 1;

}

void scankey(void)

{

uchar tmp = 0;

DDRD &= ~0X04;

DDRC = (DDRC & 0X0F) | 0XC0;

PORTD |= 0X04;

PORTC = (PORTC & 0X0F) | 0X70;

delay(2);

tmp = PINC;

if((~tmp & 0x30) != 0)

delay(2);

tmp = PINC;

if((~tmp) & (1 << 4)){

key_timer = 0;

cur_key = 2;//test

return;

}

if((~tmp) & (1 << 5)){

key_timer = 0;

cur_key = 1;//up

return;

}

PORTC = (PORTC & 0X0F) | 0Xb0;

delay(2);

tmp = PINC;

if((~tmp & 0x30) != 0)

delay(2);

tmp = PINC;

if((~tmp) & (1 << 4)){

key_timer = 0;

cur_key = 4;//switch

return;

}

if((~tmp) & (1 << 5)){

key_timer = 0;

cur_key = 3;//time

return;

}

cur_key = 0;

}

void decidekey(void)

{

if(cur_key==0 && pre_key != 0)

{

key_up[pre_key - 1] = 1;

key_chg = 1;

}

else if(cur_key!=0 && pre_key==0)

{

key_down[cur_key - 1] = 1;

key_chg = 1;

}

else

{

key_chg = 0;

}

pre_key = cur_key;

}

void port_init(void)

{

DDRB = 0xFF;

PORTB = 0X00;

DDRC |= 0X0F;

PORTC = 0X00;

DDRA |= 0X30;

PORTA &= ~0X30;

}

void sendto(uchar no, uchar data[], uchar n)

{

USART_TranStr(node, 7);

USART_Transmit(no);

USART_TranStr(data, n);

}

void zigbeeReset(void)

{

USART_TranStr("AT+RESET", 8);

}

void zigbeeSleep(uchar TH, uchar TL)

{

uchar sleep[] = {"AT+SLEEP="};

USART_TranStr(sleep, 9);

USART_Transmit(TH);

USART_Transmit(TL);

}

void setrelay(uchar op)

{

uchar setRelay[] = {"AT+SETRELAY="};

USART_TranStr(setRelay, 12);

USART_Transmit(op);

}

void timer1_init(void)

{

TCCR1A = 0xa2; //兩路PWM,匹配清零

TCCR1B = 0x19; //快速PWM模式,位數可調,預分頻1

ICR1 = 0xFFFF;

//計數上限值,此數為16位PWM,此值的多少決定PWM的位數,改變值可以改變時鐘的輸入頻率

//在1M時鐘下,OCR1A,OCR1B=1M/65536=15HZ。改為7FFF時,為30HZ,ICR1變小,OCR1A,B成比例變大

}

void main()

{

uchar data[] = {0x01};

uchar time[] = {0x03, 21, 14, 55};

uchar send_buf[] = {0x05, 0x01, 0x00, 0x00};

uchar oldcomm[] = {0x00};

uchar flag = 0;

uchar light_obj = 500;

int a = 0;

uint PID_out = 0;

uint pre_PID_out = 0;

int delta_PID_out = 0;

int PID_in = 0;

int disp_num = 0;

CLI();

PID_init(&sPID);

uart0_init();

timer1_init();

MCUCR = 0x00;

GICR = 0x00;

OCR1A = a;

//OCR1B=a; //匹配初值

DDRA |= 0X20;

PORTA = 0X00;

DDRD |= 0XF8;

PORTD &= ~0XF8;

port_init();

SEI();

delay(1000);

sendto(LIGHT_NODE, send_buf, 4);

while(1)

{

if(uart_flag == 1)

{

uart_flag = 0;

PID_in = 255 - rcv_buf[1];// * 4 - rcv_buf[2];

/*pre_PID_out = PID_out;

delta_PID_out = delta_PID(&sPID, PID_in);

PID_out += delta_PID_out;

OCR1A = PID_out;*/

PIDproc(&sPID, PID_in);

OCR1A = sPID.uk;

sendto(LIGHT_NODE, send_buf, 4);

}

scankey();

decidekey();

if(key_chg && key_up[0])

{

key_up[0] = 0;

sPID.set_point += 10;

sendto(LIGHT_NODE, send_buf, 4);

}

if(key_chg && key_up[1])

{

key_up[1] = 0;

sPID.set_point -= 10;

sendto(LIGHT_NODE, send_buf, 4);

}

if(key_chg && key_up[2])

{

key_up[2] = 0;

disp_num = 0;

}

if(key_chg && key_up[3])

{

key_up[3] = 0;

disp_num = 1;

}

(disp_num == 0)?disp(PID_in):disp(PID_out / 10);

}

}//這是PID調節光照的,妳自己慢慢看看,道理差不多

  • 上一篇:線上網路考試系統的背景目的意義和開發平臺都是什麽啊?
  • 下一篇:哪位知道有關C++的好書,就推薦給我吧!!!
  • copyright 2024編程學習大全網