/*************************************************************************************************** EME(月面反射通訊)/AMAST(業餘衛星通信)用控制器 (核心碼) 利用 控制轉向設備(定向天線) 自動/手動 達成 EME / AMAST 時透過軟件追逐目標之功能 (PCB線路圖,程式檔案在頁尾) 主核心: PIC16F877A 使用週邊: GY-26 (電子羅盤0~360)[0~3600 通訊] SCA60C N1000060 單軸傾角傳感器 (傾角器-90~+90)[0.5~4.5 VDC ] 為了要能偵測超過下限,下限建議至少定在0.8~1左右 MAX232 (與上位機通訊) 1602 (液晶顯示) 液晶顯示: 第一行 顯示 "方位角 傾角 自動A/手動M 模式" 第二行 顯示 "目前狀態" 左/右/上/下 旋轉" 支援指令: GS-232A (部份指令) C //要求 水平角度 B //要求 傾角 C2 //要求 水平 + 傾角 M //指令 前往 Mxxx 水平角度xxx W //指令 前往 Wxxx yyy 水平角度xxx 傾角yyy S //指令 All Stop R //指令 Clockwise Rotation L //指令 Counter Clockwise Rotation A //指令 CW/CCW Rotation Stop U //指令 UP Direction Rotation D //指令 DOWN Direction Rotation E //指令 UP/DOWN Direction Rotation Stop I/O定義: 定義 TRISx 1為輸入/ 0為輸出 / x 為未始用(1) (TRISA只有6個Bit) TRISA x x 0 x 0 0 0 1 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左 TRISB 0 0 0 0 0 0 0 0 <--- LCD IO 輸出 TRISC 1 0 0 0 0 0 0 0 <--- Bit01: 停右 /Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入 TRISD 0 0 0 0 0 0 0 0 <--- Bit01267:R.L.OUTPUT / Bit345:LCD command 定義 PORTx 1為高電平/ 0為低電平 / x 為未始用 (TRISA只有6個Bit)電壓輸入口設低電平/其他需要改變狀態(拉成低電平)的設成高電平/再其他亦可都設成高電平 PORTA x x 1 1 1 1 1 0 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左輸入 PORTB 1 1 1 1 1 1 1 1 <--- LCD IO 輸出 PORTC 1 0 0 0 0 0 0 0 <--- Bit01:停右輸入/Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入 PORTD 1 1 1 1 1 1 1 1 <--- Bit01267:R.L.OUTPUT (高電平 = 1 = 不動作 )/ Bit345:LCD command 接線注意 : 控制雲台轉向的繼電器實際接線時, 將110V電源其中一線接到 上(COM) 再將 上(NC)->下(COM) 以此類推 ->左-->右 這樣可以防止萬一繼電器同時動作時,110V的控制電源同時輸出(雖然程式有保護了,還是要有硬線防呆!) PS.控制線接在NO 維護記錄: 2012-07-20 ***************************************************************************************************/ #include <pic.h> //頭文件在HI-TECH安裝目錄下\HI-TECH Software\PICC\std\9.60\include #include <stdio.h> #include <string.h> #define uchar unsigned char #define uint unsigned int #define GY_26_ADDR 0xE0 //定義電子指南針器件地址(出廠默認為0XE0) #define rs RD5 //LED 命令/數據選擇 #define rw RD4 //LED 讀寫口 #define e RD3 //LED 鎖存控制 #define Dataport PORTB //LED 數據口定義 void delay_20us(uint nus); void mcu_init(void); void nms_delay(uint nms); uint get_GY_26(uchar read_begin_address,uchar GY_26_cmd); uint get_AD(void); void conversion(uint i); void cmdIU(uint i); //iic使用函數********************************// void iic_Start(void){SEN=1;while(SEN);} //啟動iic void iic_Stop (void){PEN=1;while(PEN);} //停止iic void iic_rest (void){RSEN=1;while(RSEN);} //重啟iic void iic_Write8Bit(uchar x){SSPIF=0;SSPBUF=x;while(!SSPIF);SSPIF=0;}//向iic總線寫8bit數據 uchar iic_read8Bit(void){RCEN=1;while(!BF);ACKEN=1;while(ACKEN);return SSPBUF;}//向iic總線讀8bit數據 //****LCD定位點*********012345678901234567***************// bank2 uchar dis1[18]={"---- BV4WD -----\0"}; //顯示兩行 bank2 uchar dis2[18]={"-- Waitting ! --\0"}; //開機預設的顯示畫面,等待雲臺離開死點後進入程式會刷新 bank2 unsigned int CMP_DATA; bank2 unsigned int result; bank3 uchar disAZ[14]={"+00000000000\0"}; //水平 bank3 uchar disEL[14]={"+00000000000\0"}; //傾角 bank3 uchar disAZEL[14]={"+0000+000000\0"}; //水平 + 傾角 bank1 uint AZ; // 檢測到的目前 水平角度 bank1 uint EL; // 檢測到的目前 傾角 bank1 uint cmd_AZ; // 指令 至 水平角度 bank1 uint cmd_EL; // 指令 至 傾角 //**************************************以下僅做旗標用***********// bank1 int rd_AZ; //要求 水平角度 bank1 int rd_EL; //要求 傾角 bank1 int rd_AZEL; //要求 水平 + 傾角 bank1 int rd_M; //指令 前往 Mxxx 水平角度xxx bank1 int rd_W; //指令 前往 Wxxx yyy 水平角度xxx 傾角yyy bank1 int rd_S; //指令 All Stop bank1 int rd_R; //指令 Clockwise Rotation bank1 int rd_L; //指令 Counter Clockwise Rotation bank1 int rd_A; //指令 CW/CCW Rotation Stop bank1 int rd_U; //指令 UP Direction Rotation bank1 int rd_D; //指令 DOWN Direction Rotation bank1 int rd_E; //指令 UP/DOWN Direction Rotation Stop //**************************************以上僅做旗標用***********// //***********以下變數使用 BANK1 ***************************** bank1 int RecTemp; //rs-232資料讀入暫存 bank1 uchar RecArray[12]; //將 RS-232 命令 寫入EEPROM用字串介面 //********************************************* //數據轉換,十六進制數據轉換成10進制 //輸入十六進制範圍:0x0000-0x270f(0-9999) //結果分成個十百千位,以ascii存入顯示區 //********************************************** void conversion(unsigned int i) { unsigned int j; j=i; //將j=i 使用 j 做PWM運算 AZ=i/10; /* 不需羅盤0~360度 轉 PWM 0~5vdc 時, 本區關閉 節省資源 PR2 = 0b10111110; //經實測 PR2/T2CON/CCP1CON 使用固定數值 T2CON = 0b00000100; //CCPR1L從 0~190 大約可對應 0~5vDC輸出 CCP1CON = 0b00111100; //j=0~3600 3600/19 =189(取整數) CCPR1L =(j/19)+1; //189+1=190 ;+1之後表示 0度~2度會有 "1" //所以精度大約為2度(後面定位時會可採用+/-2度及算定位完成) */ dis1[3]=i/1000+0x30; // i : 取自電子羅盤的角度 i=i%1000; //取餘數運算 dis1[4]=i/100+0x30; i=i%100; //取餘數運算 dis1[5]=i/10+0x30; i=i%10; //取餘數運算 dis1[6]=0xDF; //(度) //************************************************************* //這是電壓顯示部份,不顯示 不需運算 //************************************************************* /*顯示 羅盤0~360度 轉 PWM 0~5vdc 時,的理論電壓值 j=(((j/19)+1)*100)/38; // j : 計算出來的理論電壓 dis1[10]=j/100+0x30; j=j%100; //取餘數運算 dis1[11]=0x2E; //.(小數點) dis1[12]=j/10+0x30; j=j%10; //取餘數運算 dis1[13]=j+0x30; dis1[14]=0x30; dis1[15]=0x56; // V //以下是 計算/顯示 至 小數位 但無意義 dis1[3]=i/1000+0x30; // i : 取自電子羅盤的角度 i=i%1000; //取餘數運算 dis1[4]=i/100+0x30; i=i%100; //取餘數運算 dis1[5]=i/10+0x30; i=i%10; //取餘數運算 dis1[6]=0x2E; //.(小數點) dis1[7]=i+0x30; dis1[8]=0xDF; //(度) */ //***************************************** //將水平 度數值放入暫存區等候RS-232 調用 //***************************************** disAZ[2]=dis1[3]; //水平角度 百位 disAZ[3]=dis1[4]; //水平角度 十位 disAZ[4]=dis1[5]; //水平角度 個位 //***************************************** //將水平 + 傾角 角度放入暫存區等候RS-232 調用 //***************************************** disAZEL[2]=dis1[3]; //水平角度 百位 disAZEL[3]=dis1[4]; //水平角度 十位 disAZEL[4]=dis1[5]; //水平角度 個位 } //************************************************************************************************** //數據轉換,AD轉換結果 //輸入十六進制範圍:0x0000-0x03FF(0-1023) //結果分成個十百千位,以ascii存入顯示區 //************************************************************************************************** void conversion2(unsigned int d) { int ad1,ad2,ad3,ad4; //定義6個AD轉換臨時變量 整數常數 int 佔有 16 個 位元 //float temp,temp1; //定義4個計算臨時變量 浮點常數 float 佔有 32 個 位元 float temp,temp1,ed1,ed2; //定義4個計算臨時變量 浮點常數 float 佔有 32 個 位元 temp=d*5.0/1023; //暫存AD轉換的結果 10位AD 2的10次方=1024 temp1=temp; //將數值暫存 temp 計算電壓 / temp1 計算角度 ad1=(int)temp; //計算輸入電壓 ad2=((int)(temp*10)-ad1*10); ad3=((int)(temp*100)-ad1*100-ad2*10); ad4=((int)(temp*1000)-ad1*1000-ad2*100-ad3*10); //************************************************************* //這是電壓顯示部份,不顯示 不需運算 //************************************************************* //dis2[10]=(int)temp+0x30; //顯示 個位 //dis2[11]=0x2E; //.(小數點) //dis2[12]=((int)(temp*10)-ad1*10)+0x30; //顯示 小數第一位 //dis2[13]=((int)(temp*100)-ad1*100-ad2*10)+0x30; //顯示 小數第二位 //dis2[14]=((int)(temp*1000)-ad1*1000-ad2*100-ad3*10)+0x30; //顯示 小數第三位 //dis2[15]=0x56; // V //EEPROM_WRITE(0x08,0x01); //EEPROM_WRITE(0x09,0x04); //******************************************************************************** //(傾角器-90~+90[共180])[0.5~4.5 VDC ] 為了要能偵測超過下限,下限建議至少定在高於0.8v //4.5-0.5=4 4/2=2 (VDC)<--只取中間90度用 下限取1.5v/上限取1.5+2=3.5V/中點2.5v //******************************************************************************** ed1=1.5; //電壓下限 0度 ed2=3.5; //電壓上限 90度 //************************************************************* temp1=(temp1-ed1)*(90.0/(ed2-ed1)); //計算角度 0~90 EL=(int)temp1; ad1=((int)(temp1/10)); //十 ad2=((int)(temp1-ad1*10)); //個 ad3=((int)(temp1*100)-ad1*10-ad2); //小數 dis1[11]=((int)(temp1/10))+0x30; //顯示 十位 dis1[12]=((int)(temp1-ad1*10))+0x30; //顯示 個位 dis1[13]=0xDF; //(度) //************************************************************* //可計算/顯示 至 小數位 但無意義 //************************************************************* //dis2[6]=0x2E; //.(小數點) //dis2[7]=((int)(temp1*100)-ad1*10-ad2)+0x30; //顯示 小數第一位 //***************************************** //將傾角 度數值放入暫存區等候RS-232 調用 //***************************************** disEL[2]=0x30; //水平角度 百位 disEL[3]=dis1[11]; //水平角度 十位 disEL[4]=dis1[12]; //水平角度 個位 //***************************************** //將 傾角 角度放入暫存區等候RS-232 調用 //***************************************** disAZEL[7]=0x30; //傾角角度 百位 disAZEL[8]=dis1[11]; //傾角角度 十位 disAZEL[9]=dis1[12]; //傾角角度 個位 if(temp<ed1) //當輸入電壓低於 電壓下限 { disEL[2]=0x30; //傾角角度 百位 設0 disEL[3]=0x30; //傾角角度 十位 設0 disEL[4]=0x30; //傾角角度 個位 設0 disAZEL[7]=0x30; //水平+傾角的 傾角角度 百位 設0 disAZEL[8]=0x30; //水平+傾角的 傾角角度 十位 設0 disAZEL[9]=0x30; //水平+傾角的 傾角角度 個位 設0 dis1[11]='L'; dis1[12]='o'; } if(temp>ed2) //當輸入電壓高於 電壓上限 { disEL[2]=0x30; //傾角角度 百位 設0 disEL[3]=0x39; //傾角角度 十位 設9 disEL[4]=0x30; //傾角角度 個位 設0 disAZEL[7]=0x30; //水平+傾角的 傾角角度 百位 設0 disAZEL[8]=0x39; //水平+傾角的 傾角角度 十位 設9 disAZEL[9]=0x30; //水平+傾角的 傾角角度 個位 設0 dis1[11]='O'; dis1[12]='v'; } } //************************************************************************************************** //數據轉換,ascii 轉換成 十六進制數據 //************************************************************************************************** void con_WB(void) { unsigned int k,p; k=0; p=0; k=(RecArray[1]-0x30)*100; k=k+(RecArray[2]-0x30)*10; k=k+(RecArray[3]-0x30); if(RecArray[0]=='M'|RecArray[0]=='W') { cmd_AZ=(int)k; } /* if(k>=0xFF) //寫入 EEPROM 需耗費時間較長 不需要時不寫入 { k=k-0xff; //大於 256 EEPROM_WRITE(0x00,0x01); //寫入 水平數值 高位數 至EEPROM 位址0x00 EEPROM_WRITE(0x01,k); //寫入 水平數值 低位數 至EEPROM 位址0x01 } else { EEPROM_WRITE(0x00,0x00); //寫入 水平數值 高位數 至EEPROM 位址0x00 EEPROM_WRITE(0x01,k); //寫入 水平數值 低位數 至EEPROM 位址0x01 } */ if(rd_W==1) { p=(RecArray[5]-0x30)*100; p=p+(RecArray[6]-0x30)*10; p=p+(RecArray[7]-0x30); if(RecArray[0]=='W') { cmd_EL=(int)p; } /* if(p>=0xFF) //寫入 EEPROM 需耗費時間較長 不需要時不寫入 { p=p-0xff; //大於 256 EEPROM_WRITE(0x03,0x01); //寫入 傾角數值 高位數 至EEPROM 位址0x03 EEPROM_WRITE(0x04,p); //寫入 傾角數值 低位數 至EEPROM 位址0x04 } else { EEPROM_WRITE(0x03,0x00); //寫入 傾角數值 高位數 至EEPROM 位址0x03 EEPROM_WRITE(0x04,p); //寫入 傾角數值 低位數 至EEPROM 位址0x04 } */ } } //************************************************************************************************** //單片機初始化 //************************************************************************************************** void mcu_init(void) { //TRISC=0x80; //IIC通信引腳設為輸入 SSPSTAT = 0x80; //IIC設置 SSPCON = 0x38; //IIC設置 SSPCON2 = 0x00; //IIC設置 SSPADD = 50; //IIC設置 } //************************************************************************************************** //延時大約20us //************************************************************************************************** void delay_20us(uint nus) { uchar i; while(--nus){ for(i=2;i>0;i--); } } //************************************************************************************************** //延時大約1ms //************************************************************************************************** void nms_delay(uint nms) { while(nms--) delay_20us(50); } //************************************************************************************************** //延時 //************************************************************************************************** void delay(uint time) { uint i,j; for(i = 0;i < time; i++); { for(j = 0;j <30; j++); } } //************************************************************************************************** //從IIC總線獲得電子指南針GY-26數據 //從開始地址連續讀出兩個8bit的值,併合成16bit數據 //************************************************************************************************** uint get_GY_26(uchar read_begin_address,uchar GY_26_cmd) { unsigned int temp; iic_Start(); //iic啟動時序 iic_Write8Bit(GY_26_ADDR); //寫指南針器件地址 iic_Write8Bit(0); //寫命令 iic_Write8Bit(GY_26_cmd); //寫指南針命令 iic_Stop(); //iic寫停止時序 nms_delay(60); //延時,可執行其他程序 原始值:55 iic_Start(); //iic啟動時序 ACKDT = 0; //允許應答ACK //******************************************************************************* //需修正磁偏角時使用「台灣磁偏角目前試定為3.5度」 //第一次使用時最好修正,因為GY-26大部分修正偏角是6度(或10度) //******************************************************************************* //iic_Write8Bit(0x03); //發送設定磁偏角高8位命令。 //iic_Write8Bit(0x00); //發送磁偏角高8位的數據。 //iic_Write8Bit(0x03); //發送設定磁偏角低8位命令 //iic_Write8Bit(0x23); //發送磁偏角低8位的數據。此時磁偏角被設定為3.5度 iic_Write8Bit(GY_26_ADDR); //寫指南針器件地址 iic_Write8Bit(read_begin_address); //寫指南針內部數據地址 iic_rest(); //iic重啟時序 iic_Write8Bit(GY_26_ADDR+1); //指南針器件地址+1=讀 temp=iic_read8Bit(); //讀出8位數據 temp<<=8; //保存數據 ACKDT = 1; //允許應答NO_ACK temp+=iic_read8Bit(); //讀出8位數據 iic_Stop(); //發送停止時序 return temp; //返回本次測量數值 } //************************************************************************************************** //從AN0讀取轉換電壓的相對值 //從ADRESH ADRESL 讀出兩個8bit的值,併合成16bit數據 //************************************************************************************************** uint get_AD() { unsigned int temp; result=0; //轉換結果清0 ADGO=0x01; //開啟轉換過程 delay(50); //保證採樣延時 //ADGO=0x01; ////ADGO=1放在此採樣不行 while(ADGO); //等待轉換完成 temp=ADRESH; //讀出8位數據 temp<<=8; //保存數據 temp+=ADRESL; //讀出8位數據 return temp; //返回本次測量數值 } //************************************************************************************************** //IO初始化操作 //定義 TRISx 1為輸入/ 0為輸出 / x 為未始用(1) (TRISA只有6個Bit) // TRISA x x 0 x 0 0 0 1 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左 // TRISB 0 0 0 0 0 0 0 0 <--- LCD IO 輸出 // TRISC 1 0 0 0 0 0 0 0 <--- Bit01:
停右 /Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入 // TRISD 0 0 0 0 0 0 0 0 <--- Bit01267:R.L.OUTPUT / Bit345:LCD command // //定義 PORTx 1為高電平/ 0為低電平 / x 為未始用 // (TRISA只有6個Bit)電壓輸入口設低電平/其他需要改變狀態(拉成低電平)的設成高電平/再其他亦可都設成高電平 // PORTA x x 1 1 1 1 1 0 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左輸入 // PORTB 1 1 1 1 1 1 1 1 <--- LCD IO 輸出 // PORTC 1 0 0 0 0 0 0 0 <--- Bit01:停右輸入/Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入 // PORTD 1 1 1 1 1 1 1 1 <--- Bit01267:R.L.OUTPUT (高電平 = 1 = 不動作 )/ Bit345:LCD command //************************************************************************************************** void IO_init(void) { TRISA=0x01; //RA0設置為輸入 00 0001 PORTA=0x3e; //設置RA0為低電平 TRISC=0x80; //RC7設置為輸入 1000 0000 PORTC=0xff; //初始化為高電平 TRISB=0x00; //RB設置為輸出 LCD IO PORTB=0xff; //初始化為高 LCD IO 為高電平 TRISD=0x00; //RD設置為輸出 LCD command PORTD=0b11111111; //初始化 LCD command(Bit345) 為高電平 /R.L.OUTPUT為高電平 } //************************************************************************************************** //雲臺初始化操作 (離開限位點) //向上轉3秒 向下轉2秒 //向左轉3秒 向右轉2秒 //************************************************************************************************** void Init_wt(void) { /* RD0=0x00; RD1=0x00; RD6=0x00; RD7=0x00; nms_delay(1000); RD2=0x01; //RD2 失能(亮) nms_delay(1000); //可將訊號接至 雲臺旁 閃爍紅燈警示 RD2=0x00; //RD2 致能(確認完成開機,控制雲臺電源可輸出[實驗板LED亮->熄滅]) nms_delay(1000); //等待 進入旋轉初始化 RD0=0x01; //指令 UP Direction Rotation RD6=0x01; //指令 Counter Clockwise Rotation nms_delay(3000); RD0=0x00; //指令 UP Direction Rotation RD6=0x00; //指令 Counter Clockwise Rotation RD0=0x00; //指令 UP Direction Rotation nms_delay(500); RD1=0x01; //指令 DOWN Direction Rotation RD7=0x01; //指令 Clockwise Rotation nms_delay(3000); RD1=0x00; //指令 DOWN Direction Rotation RD7=0x00; //指令 Clockwise Rotation nms_delay(500); */ nms_delay(1000); //等待 //******************************************************************************* //完成轉動後重新將LCD內容刷新 //******************************************************************************* dis1[0]='A'; dis1[1]='Z'; dis1[2]=':'; dis1[3]='0'; dis1[4]='0'; dis1[5]='0'; dis1[6]=' '; dis1[7]=' '; dis1[8]='E'; dis1[9]='L'; dis1[10]=':'; dis1[11]='0'; dis1[12]='0'; dis1[13]=' '; dis1[14]=' '; dis1[15]=' '; dis2[0]='-'; dis2[1]='-'; dis2[2]='-'; dis2[3]='-'; dis2[4]='-'; dis2[5]='-'; dis2[6]='-'; dis2[7]='-'; dis2[8]='-'; dis2[9]='-'; dis2[10]='-'; dis2[11]='-'; dis2[12]='-'; dis2[13]='-'; dis2[14]='-'; dis2[15]='-'; } //************************************************************************************************** //向LCD寫一命令 //************************************************************************************************** wcode(uchar t) { rs=0; // 寫的是命令 rw=0; // 寫狀態 e=1; //使能 Dataport=t; //寫入命令 delay(45); //等待寫入,如果時間太短,會導致液晶無法顯示 e=0; //數據的鎖定 } //************************************************************************************************** //向LCD寫一數據 //************************************************************************************************** wdata(uchar t) { rs=1; // 寫的是數據 rw=0; // 寫狀態 e=1; //使能 Dataport=t; //寫入數據 delay(45); //等待寫入,如果時間太短,會導致液晶無法顯示 e=0; //數據的鎖定 } //************************************************************************************************** //LCD顯示第一行 //************************************************************************************************** xian1(void) { uchar i; wcode(0x80); //設置第一行顯示地址 for(i=0;i<16;i++) //循環16次,寫完1行 { wdata(dis1[i]); //寫入該行數據 } } //************************************************************************************************** //LCD顯示第二行 //************************************************************************************************** xian2(void) { uchar i; wcode(0xc0); //設置第二行顯示地址 for(i=0;i<16;i++) //循環16次,寫完1行 { wdata(dis2[i]); //寫入該行數據 } } //************************************************************************************************** //LCD 初始化 //************************************************************************************************** InitLCD(void) { wcode(0x01); //清屏 wcode(0x06); //輸入方式控制,增量光標不移位 wcode(0x0e); //顯示開關控制 wcode(0x38); //功能設定:設置16x2顯示,5x7顯示,8位數據接口 } //************************************************************************************************** //初始化串口 //************************************************************************************************** void init_com( void ) { TXSTA=0x24;//發送數據控制位配置00100100,異步方式、高波特率,波特率=Fosc/16*(SPBTG+1); //TXSTA寄存器的D5(TXEN)=1,啟動UART的發送功能 RCSTA=0x90;//接收數據控制位配置10010000,設置連續接收數據 //RCSTA寄存器的D4(CREN)=1,啟動UART的接收功能 SPBRG=25; //設置波特率9600,系統時鐘4MHZ,波特率=4000000/16/(25+1)=9615(Bps) 51 //設置波特率4800,系統時鐘4MHZ,波特率=4000000/16/(51+1)=4807(Bps) RCIE=1; //接收中斷使能 TXIE=0; //發送中斷使/失能 PEIE=1; //INTCON的D6(PEIE)=1,外圍中斷開關打開 RCIF=0; RCREG=0; GIE=1; //總中斷開啟 } //************************************************************************************************** //寫RS-232 //************************************************************************************************** void WriteByte(unsigned char byte) { while(!TXIF); { TXREG = byte; } } //************************************************************************************************** //向RS-232寫一字串數據 //************************************************************************************************** void WriteStringConst(const unsigned char* str) { int n,m; for(n=0;n<=11;n++) { //TXREG = str[n]; WriteByte(str[n]); } } //************************************************************************************************** //雲臺轉向控制 // 選用的雲臺 傾角 動作時會稍微干擾電子羅盤 // 雖然已經將 羅盤 與 馬達 距離拉開,但在做 傾角 動作時,還是先 不旋轉 以免因為誤判角度而亂轉 //************************************************************************************************** conTIO(void) { RD0= !rd_U; //指令 UP Direction Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作) RD1= !rd_D; //指令 DOWN Direction Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作) if(rd_U==0&&rd_D==0) //傾角動作優先,傾角動作完成之後再旋轉 { RD6= !rd_L; //指令 Counter Clockwise Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作) RD7= !rd_R; //指令 Clockwise Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作) } } //************************************************************************************************** //check 資料要求 COMMAND // //int rd_AZ; //要求 水平角度 //int rd_EL; //要求 傾角 //int rd_AZEL; //要求 水平 + 傾角 //************************************************************************************************** cmdCHK(void) { if(rd_AZ==1) { WriteStringConst(disAZ); rd_AZ=0; } if(rd_EL==1) { WriteStringConst(disEL); rd_EL=0; } if(rd_AZEL==1) { WriteStringConst(disAZEL); rd_AZEL=0; } } //************************************************************************************************** //雲臺自動轉向 COMMAND // //int rd_M; //自動指令 前往 Mxxx 水平角度xxx //int rd_W; //自動指令 前往 Wxxx yyy 水平角度xxx 傾角yyy //int rd_S; //指令 All Stop //int rd_R; //指令 Clockwise Rotation //int rd_L; //指令 Counter Clockwise Rotation //int rd_A; //指令 CW/CCW Rotation Stop //int rd_U; //指令 UP Direction Rotation //int rd_D; //指令 DOWN Direction Rotation //int rd_E; //指令 UP/DOWN Direction Rotation Stop //************************************************************************************************** void turn_cmd(void) { //if(cmd_AZ>AZ&&(cmd_AZ-AZ)>3 &&(cmd_AZ-AZ)<30) if(cmd_AZ>AZ&&(cmd_AZ-AZ)>3) { nms_delay(100); //防止繼電器高速跳動 rd_R=1; rd_L=0; } //if(AZ>cmd_AZ&&(AZ-cmd_AZ)>3&&(AZ-cmd_AZ)<30) if(AZ>cmd_AZ&&(AZ-cmd_AZ)>3) { nms_delay(100); //防止繼電器高速跳動 rd_R=0; rd_L=1; } //if(AZ >345 && cmd_AZ <15 ) // tracking cross left 過 360' //{ // rd_R=1; //} //if(AZ <15 && cmd_AZ >345 ) // tracking cross right 過 360' //{ // rd_L=1; //} if(cmd_AZ>AZ&&(cmd_AZ-AZ)<3) { rd_R=0; } if(AZ>cmd_AZ&&(AZ-cmd_AZ)<3) { rd_L=0; } if(rd_R==0&&rd_L==0) { rd_M=0; } if(rd_W==1) { //if(cmd_EL>EL&&(cmd_EL-EL)>2&&(cmd_EL-EL)<20&&EL<90) if(cmd_EL>EL&&(cmd_EL-EL)>2&&EL<90) { nms_delay(100); //防止繼電器高速跳動 rd_U=1; rd_D=0; } //if(EL>cmd_EL&&(EL-cmd_EL)>2&&(EL-cmd_EL)>20&&EL>0) if(EL>cmd_EL&&(EL-cmd_EL)>2&&EL>0) { nms_delay(100); //防止繼電器高速跳動 rd_D=1; rd_U=0; } if(cmd_EL>EL&&(cmd_EL-EL)<2) { rd_U=0; } if(EL>cmd_EL&&(EL-cmd_EL)<2) { rd_D=0; } if(EL==0&&cmd_EL==0) { rd_D=0; rd_U=0; } if(rd_R==0&&rd_L==0&&rd_U==0&&rd_D==0) { rd_W=0; } } if(rd_A==1) { rd_R=0; rd_L=0; rd_A=0; } if(rd_E==1) { rd_D=0; rd_U=0; rd_E=0; } } //************************************************************************************************** //check 雲臺轉向 指示 及 過頭.回一點 控制 // //int rd_M; //自動指令 前往 Mxxx 水平角度xxx //int rd_W; //自動指令 前往 Wxxx yyy 水平角度xxx 傾角yyy //int rd_S; //指令 All Stop //int rd_R; //指令 Clockwise Rotation //int rd_L; //指令 Counter Clockwise Rotation //int rd_A; //指令 CW/CCW Rotation Stop //int rd_U; //指令 UP Direction Rotation //int rd_D; //指令 DOWN Direction Rotation //int rd_E; //指令 UP/DOWN Direction Rotation Stop //************************************************************************************************** void turn_dsp(void) { if(dis1[11]=='L'&&dis1[12]=='o'&&result>>0) //指令 傾角過低 low(回頭)(當 傾角 輸入=0V(將該腳位接地) 時 不做「過頭回一點」的控制) { RD1=!0x00; RD0=!0x01; nms_delay(300); RD1=!0x00; RD0=!0x00; } if(dis1[11]=='O'&&dis1[12]=='v'&&result>>0) //指令 傾角過高 over(回頭)(當 傾角 輸入=0V(將該腳位接地) 時 不做「過頭回一點」的控制) { RD0=!0x00; RD1=!0x01; nms_delay(300); RD1=!0x00; RD0=!0x00; } //******012345678901234567***************// //dis2{"Turn! Right Down\0"}; // {"Turn! Left UP \0"}; // {"------STOP------\0"}; //***********************************// if(rd_U==1|rd_D==1|rd_L==1|rd_R==1) { dis2[0]='T'; dis2[1]='u'; dis2[2]='r'; dis2[3]='n'; dis2[4]='!'; dis2[5]=0x20; dis2[6]=0x20;; dis2[7]=0x20;; dis2[8]=0x20;; dis2[9]=0x20;; dis2[10]=0x20; dis2[11]=0x20;; dis2[12]=0x20;; dis2[13]=0x20;; dis2[14]=0x20;; dis2[15]=0x20;; } if(rd_U==1) { dis2[12]=0x20; dis2[13]='U'; dis2[14]='P'; dis2[15]=0x20; } if(rd_D==1) { dis2[12]='D'; dis2[13]='o'; dis2[14]='w'; dis2[15]='n'; } if(rd_L==1) { dis2[6]='L'; dis2[7]='e'; dis2[8]='f'; dis2[9]='t'; dis2[10]=0x20; } if(rd_R==1) { dis2[6]='R'; dis2[7]='i'; dis2[8]='g'; dis2[9]='h'; dis2[10]='t'; } if(rd_U==0&&rd_D==0) { dis2[12]=0x20; dis2[13]=0x20; dis2[14]=0x20; dis2[15]=0x20; } if(rd_L==0&&rd_R==0) { dis2[6]=0x20; dis2[7]=0x20; dis2[8]=0x20; dis2[9]=0x20; dis2[10]=0x20; } if(rd_U==0&&rd_D==0&&rd_L==0&&rd_R==0) { dis2[0]='-'; dis2[1]='-'; dis2[2]='-'; dis2[3]='-'; dis2[4]='-'; dis2[5]='-'; dis2[6]='-'; dis2[7]='-'; dis2[8]='-'; dis2[9]='-'; dis2[10]='-'; dis2[11]='-'; dis2[12]='-'; dis2[13]='-'; dis2[14]='-'; dis2[15]='-'; } } //********************************************* //雲臺 手動 轉向 COMMAND // //int rd_S; //指令 All Stop //int rd_R; //指令 Clockwise Rotation //int rd_L; //指令 Counter Clockwise Rotation //int rd_A; //指令 CW/CCW Rotation Stop //int rd_U; //指令 UP Direction Rotation //int rd_D; //指令 DOWN Direction Rotation //int rd_E; //指令 UP/DOWN Direction Rotation Stop //********************************************** void PB_cmd(void) { rd_M=0; rd_W=0; rd_L=0; rd_R=0; rd_A=0; rd_U=0; rd_D=0; rd_E=0; rd_S=0; if(RA2==0) //檢查按鍵 上 { nms_delay(5); if(RA2==0) { rd_D=0; //互鎖 rd_U=1; } } else { rd_U=0; } if(RA3==0) //檢查按鍵 下 { nms_delay(5); if(RA3==0) { rd_U=0; //互鎖 rd_D=1; } } else { rd_D=0; } if(RC1==0) //檢查按鍵 左 { // (RA4 不可以用(無法改變數值+狀態不定) /改用 RC1) nms_delay(5); if(RC1==0) { rd_R=0; rd_L=1; } } else { rd_L=0; } if(RA5==0) //檢查按鍵 右 { nms_delay(5); if(RA5==0) { rd_L=0; rd_R=1; } } else { rd_R=0; } if(RC0==0) //檢查按鍵 停 { nms_delay(5); if(RC0==0) { rd_L=0; rd_R=0; rd_U=0; rd_D=0; rd_S=1; } } else { rd_S=0; } } //********************************************* //CHECK STOP COMMAND //int rd_S; //指令 All Stop //********************************************** void CHK_stop(void) { if(RC0==0) //檢查按鍵 停 { nms_delay(5); if(RC0==0) { rd_L=0; rd_R=0; rd_U=0; rd_D=0; rd_S=1; } } else { rd_S=0; } } //************************************************************************************************** //串口中斷函數 //接收要求或指令 並改變旗標 //int rd_AZ; //要求 水平角度 //int rd_EL; //要求 傾角 //int rd_AZEL; //要求 水平 + 傾角 // //int rd_M; //指令 前往 Mxxx 水平角度xxx //int rd_W; //指令 前往 Wxxx yyy 水平角度xxx 傾角yyy // //int rd_R; //指令 Clockwise Rotation //int rd_L; //指令 Counter Clockwise Rotation //int rd_A; //指令 CW/CCW Rotation Stop // //int rd_U; //指令 UP Direction Rotation //int rd_D; //指令 DOWN Direction Rotation //int rd_E; //指令 UP/DOWN Direction Rotation Stop // //int rd_S; //指令 All Stop //**************************************************************************************************\ void interrupt usart(void) { int i; if(RCIF) { RecArray[i] = RCREG; i=i++; //if(RCREG==0x0D|RCREG==0x20) if(RCREG==0x0D) { //if(RecArray[0]==0x43&&rd_M!=1&&rd_W!=1) // 如果抓到開頭為 C 並且無自動指令 M W if(RecArray[0]==0x43) // 如果抓到開頭為 C 並且無自動指令 M W { rd_AZ=1; } //if(RecArray[0]==0x42&&rd_M!=1&&rd_W!=1) // 如果抓到開頭為 B 並且無自動指令 M W if(RecArray[0]==0x42) // 如果抓到開頭為 B 並且無自動指令 M W { rd_EL=1; } //if(RecArray[0]==0x43 && RecArray[1]==0x32&&rd_M!=1&&rd_W!=1) // 如果抓到開頭為 C2 並且無自動指令 M W if(RecArray[0]==0x43 && RecArray[1]==0x32) // 如果抓到開頭為 C2 並且無自動指令 M W { rd_AZ=0; rd_EL=0; rd_AZEL=1; } if(RecArray[0]==0x4D) // 如果抓到開頭為 M 水平自動指令 { rd_M=1; } if(RecArray[0]==0x57) // 如果抓到開頭為 W 水平+傾角自動指令 { rd_W=1; } if(RecArray[0]==0x52) // 如果抓到開頭為 R { rd_L=0; rd_R=1; } if(RecArray[0]==0x4C) // 如果抓到開頭為 L { rd_R=0; rd_L=1; } if(RecArray[0]==0x41) // 如果抓到開頭為 A { rd_L=0; rd_R=0; rd_A=1; } if(RecArray[0]==0x55) // 如果抓到開頭為 U { rd_D=0; rd_U=1; } if(RecArray[0]==0x44) // 如果抓到開頭為 D { rd_U=0; rd_D=1; } if(RecArray[0]==0x45) // 如果抓到開頭為 E { rd_U=0; rd_D=0; rd_E=1; } if(RecArray[0]==0x53) // 如果抓到開頭為 S { rd_M=0; rd_W=0; rd_L=0; rd_R=0; rd_A=0; rd_U=0; rd_D=0; rd_E=0; rd_S=1; } i=0; } if(i>=11) { i=0; //如果超過12(0~11)個字元就把i歸零(一直重複,將此次訊號收完,防止溢位) } } } //************************************************************************************************** //主函數 //************************************************************************************************** main() { uchar cntl; //__CONFIG(XT&WDTEN&LVPDIS);//配置,設置為晶振XT方式振蕩,看門狗,禁低電壓編程 __CONFIG(XT&WDTDIS&LVPDIS);//配置,設置為晶振XT方式振蕩,禁看門狗,禁低電壓編程 mcu_init(); //晶片初始化 IO_init(); //IO初始化 init_com(); //初始化串口 InitLCD(); //初始化1602 xian1(); //顯示 等待訊息 xian2(); //顯示 等待訊息 Init_wt(); //初始化雲臺(確保不會正好在 Over0 或是 Over360) while(1) //進入while死循環 { result=get_AD(); //讀取傾角電壓 conversion2(result); //數據轉換出個,十,百,千 位 if(rd_U==0&&rd_D==0) { CMP_DATA=get_GY_26(1,0x31); //讀取角度 conversion(CMP_DATA); //數據轉換出個,十,百,千 位 } xian1(); //顯示 第1行刷新 xian2(); //顯示 第2行刷新 conTIO(); cmdCHK(); if(RA1==1) //檢查模式 自動=1 手動=0 { dis1[15]='A'; if(rd_M==1|rd_W==1) { con_WB(); //轉換指令後之「文字」變成「數字」 turn_cmd(); //檢測是否要旋轉 //turn_dsp(); //旋轉狀態顯示 } CHK_stop(); //檢測是否STOP有按下 turn_dsp(); //旋轉狀態顯示 } if(RA1==0) //檢查模式 自動=1 手動=0 { dis1[15]='M'; rd_M=0; rd_W=0; PB_cmd(); //掃描按鍵狀態 turn_dsp(); //旋轉狀態顯示 } } } |
手做小玩意兒(DIY) >