單片機采樣送can格式數據,后端通過232轉can傳輸
單片機源程序如下:
- //////////////////////////////////////////////////////////////////////////////////////////////
- //編制的地面電源軟件。發生過數組超限的情況軟件仿真調試完成時間2010805, //
- // 該單片機的定時器、AD轉換器、串行口都與以前不同,需要特別注意。
- //////////////////////////////////////////////////////////////////////////////////////////////
- #include <STC15.H>
- // #include <absacc.h>
- // #include <math.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define ulong unsigned long
- //buf[0]~buf[3]是報頭,buf[4]、buf[5]是輸出電壓BCD碼uf[6]、buf[7]是輸出電流BCD碼,buf[8]是輸出狀態標志1,
- //buf[9]、buf[10]是溫度的BCD碼,buf[11]是輸入狀態標志2,buf[12]、buf[13]暫時未使用。
- uchar idata buf[45]={1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2};
- uint idata bufint[40]={0x0001,0x0002,0x0004,0x0008,0x0016,0x0032,0x0064,0x0128,0x0256,0x0512,0x1024,0x2048,0x4096,0x8192};
- uchar code zifu1[40]={111,104,7,4,5,6,7,8,9,8,53,111,104,3,4,5,6,7,8,9,8,53,111,104,2,1,8,9,8,6,5,7,53};
- uchar code zifu2[20]={1,2,4,8,16,32,3,2,1,2,3,4,5,6,7};
- // unsigned int idata gz_time[10]={0,0,0,0,0};
- sbit ADC_1=P1^0; //電壓測量
- sbit ADC_2=P1^1; //電流測量
- sbit ADC_3=P1^2; //溫度測量
- sbit TS=P2^5; //調試開關
- sbit DJ=P2^1; //開關KGUAN
- sbit SJ=P2^0; //發收FS
- // sfr ADC_CONTR=0xBC; //ADC控制寄存器
- // sfr ADC_RES=0xBD; //ADRJ=0時,ADC結果高8位;ADRJ=1時,B1B0位ADC結果的高兩位ADC_RES9 ADC_ RES8
- // sfr ADC_RESL=0xBE; //ADRJ=0時,B1B0位ADC結果的低兩位ADC_RES1 ADC_ RES0;ADRJ=1時,ADC結果低8位
- // sfr WDT_CONTR=0xC1;
- // sfr AUXR=0x8E;
- // sfr AUXR1=0xA2;
- // sfr P1ASF=0x9D;
- // sfr CLK_DIV=0x97; //ADRJ控制ADC結果存放的位置
- // sfr T2H=0xD6; //需要定義,TH2不定義則不寫分頻系數進0xD6,導致定時器2不工作,串行口不發送數據,TI始終為0,不置1,無數據輸出。
- // sfr T2L=0xD7; //需要定義,TL2不定義則不寫分頻系數進0xD7
- // sfr P3M1=0xb1;
- // sfr P3M0=0xb2;
- // sfr P2M1=0x95;
- // sfr P2M0=0x96;
- // sfr P1M1=0x91;
- // sfr P1M0=0x92;
- #define ADC_POWER 0x80 //ADC電源控制位
- #define ADC_FLAG 0x10 //ADC完成標志位
- #define ADC_START 0x08 //ADC開始控制位
- void timer0_ISR ( ) interrupt 1 using 2 //10毫秒@11.0592MHz時鐘
- {
- buf[25]=buf[25]+1; //中斷次數計數,也就是計時。buf[25]記錄中斷的次數,達到10次后清零
- }
- void time0Init() //定時器0初始化
- {
- AUXR &= 0x7F; //定時器時鐘12T模式
- TMOD &= 0xF0; //設置定時器0模式
- TL0=0x00; //10ms中斷一次,(10ms)TH0TL0=65536-11059200/12/100=55536=0xdc00,(10ms)TH0TL0=65536-12000000/12/100=55536=0xd8f0,
- TH0=0xdc; // TH0=0xdc;TL0=0x00.(50ms)H0TL0=65536-11059200/12/20=19456=0x4c00
- TF0=0; //清除TF0標志
- TR0=1; //定時器0開始計時
- EA=1;
- ET0=1;
- }
- void inituart() //串行口、定時器0初始化函數
- {
- SCON=0x50; //串行口工作在方式1。01010000
- AUXR1=0x40; //將串口定義到P3.6、P3.7,AUXR1=01000000,
- AUXR |= 0x01; //定時器0、2不分頻,選擇定時器2作為串口1的波特率發生器
- T2H=0xff; //設定波特率重裝值TH2TL2=65536-11059200/4/11520/12=65516=0xffecTH2TL2=65536-12000000/4/9600/12=65510=0xffe6。
- T2L=0xe8; //9600bps@11.0592MHzTH2TL2=65536-11059200/4/9600/12=65512=0xffe8;TH2TL2=65536-11059200/4/1200/12=65344=0xff40
- PCON=0x00; //波特率不加倍
- AUXR |= 0x10; //TR2=1; //啟動T/C2
- P3M1=0x00;
- P3M0=0x00;
- }
- //void UartInit(void) //9600bps@11.0592MHz
- //{
- // SCON = 0x50; //8位數據,可變波特率
- // AUXR |= 0x01; //串口1選擇定時器2為波特率發生器
- // AUXR &= 0xFB; //定時器2時鐘為Fosc/12,即12T
- // T2L = 0xE8; //設定定時初值
- // T2H = 0xFF; //設定定時初值
- // AUXR |= 0x10; //啟動定時器2
- //}
- void delay(uchar delay_time) //延時函數。
- {uchar n;
- uint m;
- for (n=0;n<delay_time;n++)
- {
- for (m=0;m<10;m++)
- WDT_CONTR=0x3C;
- }
- }
- void set_p1_adc_channel()
- {
- uchar n;
- P1=0x00;
- ADC_CONTR=0xE0; //開啟AD電源 (11100000)
- ADC_RES=0; //AD結果高位清0
- ADC_RESL=0; //AD結果低2位清0
- P1ASF=0x07; //P1^0、P1^1和P1^2設為AD口。
- n=1;
- delay(n); //穩定電源延時。
- }
- void adcyang(uchar idata *d,q) /*A/D變換q將數據放在不同的位置*/
- {uchar i,j;
- ADC_CONTR=ADC_CONTR&0xE0; //a/d的數據存放:buf[35]buf[36]電壓、buf[37]buf[38]電流、buf[39]buf[40]溫度。
- i=0;
- ADC_CONTR=ADC_CONTR|i; //選擇P1^0進行A/D轉換,采集電壓值
- i=8;
- ADC_CONTR=ADC_CONTR|i; //啟動A/D。
- j=0;
- while(j==0)
- {
-
- j=ADC_CONTR&0x10;
- if (buf[25]>0x05) // //調試用,防止不斷循環
- {j=0x01;}
- }
- i=0xEF;
- ADC_CONTR=ADC_CONTR&i; //清A/D標志。
- d[q]=ADC_RES; //P1^0的A/D電壓值結果高8位。
- d[q+1]=ADC_RESL; //P1^0的A/D電壓值結果低2位。
- ADC_CONTR=ADC_CONTR&0xE0; //
- i=1;
- ADC_CONTR=ADC_CONTR|i; //選擇P1^1進行A/D轉換,采集電流值,
- i=8;
- ADC_CONTR=ADC_CONTR|i; //啟動A/D。
- j=0;
- while(j==0)
- {
- j=ADC_CONTR&0x10;
- if (buf[25]>0x05) //調試用,防止不斷循環
- {j=0x01;}
- }
- i=0xEF;
- ADC_CONTR=ADC_CONTR&i; //清A/D標志。
- d[q+2]=ADC_RES; //P1^1的A/D電流值結果高8位。
- d[q+3]=ADC_RESL; //P1^1的A/D電流值結果低2位。
- ADC_CONTR=ADC_CONTR&0xE0; //A/D準備
- i=2;
- ADC_CONTR=ADC_CONTR|i; //選擇P1^2進行A/D轉換。
- i=8;
- ADC_CONTR=ADC_CONTR|i; //啟動A/D。
- j=0;
- while(j==0)
- {
- j=ADC_CONTR&0x10;
- if (buf[25]>0x05) //調試用,防止不斷循環
- {j=0x01;}
- }
- i=0xEF;
- ADC_CONTR=ADC_CONTR&i; //清A/D標志。
- d[q+4]=ADC_RES; //P1^2的A/D溫度值結果高8位。
- d[q+5]=ADC_RESL; //P1^2的A/D溫度值結果低2位。
- }
-
- void bcdzhuanhua(unsigned int m,uchar a)
- {
- uchar i,p,q,r;
- uint j,k,n,h,l,t;
- q=0;
- r=0;
- n=0;
-
- for(i=0;i<=14;i++) //二進制位權存在,加上一個字分為4位的BCD碼。共檢查14位。15、16位沒有這么大的數。
- {
- //m是要轉換的值。
- j=m;
- j>>=i; //從最低位開始考察m。
- q=(uchar)j; //將j轉換換為字節
- q=0x01&q;
- if(q>0) //考察m的每一位。
- {
- k=bufint[i]; //bufint[i]是二進制i的位權。
- h=0x000f;
- for(p=0;p<=3;p++) //p是BCD碼的位置
- {
- l=n;
- t=(k&h);
- if(t>0)
- {
- n=n+t; //k的每組四位值最大為9。n是十進制數同樣。不用考慮k、與n的值超過9,但要考慮進位。
- t=h;
- t<<=4;
- l=t&l;
- t=t&n;
- if(t>l) //考慮進位
- {
- l=0x6666&h;
- n=n+l; //有進位則加6
- }
- l=n&0x000f;
- if(l>=0x000a) //還需要檢查十分位是9的情況。
- {
- n=n-0x000a+0x0010; //減10向十位進位。
- }
- l=n&0x00f0;
- if(l>=0x00a0)
- {
- n=n-0x00a0+0x0100; //減100向佰位進位。
- }
- l=n&0x0f00;
- if(l>=0x0a00)
- {
- n=n-0x0a00+0x1000; //減1000向千位進位。
- }
- }
- h<<=4;
- }
- }
- }
- j=0x00ff; //這里有錯,拆成一個字8位
- j=n&j;
- buf[a+2]=(uchar)j;
- j=0xff00;
- j=n&j;
- j>>=8;
- buf[a+1]=(uchar)j;
- }
- void test_v( uint m )
- {
- int f;
- uchar i;
- bufint[14]=m; //buf[14]是電壓的16進制值。
- buf[8]=buf[8]&0xfc; //電壓正常,buf[8]是狀態字,狀態字的B0、B1置0.
- f=m-5200; //5200是520V電壓,f值小于5200V位是低壓狀態。
- if(f<0)
- {
- DJ=1; //發光二極管亮報警。
- SJ=1; //蜂鳴器報警
- buf[8]=buf[8]+0x02; //狀態字B1置1;
- }
- f=m-5800; //5800是580V電壓f值大于580V位是高壓狀態。
- if(f>0)
- {
- DJ=1; //發光二極管亮報警?
- SJ=1; //蜂鳴器報警
- buf[8]=buf[8]+0x01; //狀態字B0置1
- }
- i=buf[8]&0x1f;
- if(i==0)
- {
- DJ=0; //發光二極管停止報警
- SJ=0; //蜂鳴器停止報警
- }
- }
- void test_I( uint m )
- {
- int f;
- uchar i;
- bufint[15]= bufint[16]; // bufint[15]~ bufint[19]是每100ms采樣的電流值。
- bufint[16]= bufint[17];
- bufint[17]= bufint[18];
- bufint[18]= bufint[19];
- bufint[19]=m;
- buf[8]=buf[8]&0xe7; //電流正常,buf[8]是狀態字,狀態字的B3置0.
- f=bufint[15]-m;
- if(f>768) //768是電流掉9A的值,768=9/12*1024,處理掉電流報警。
- {
- DJ=1; //發光二極管亮報警。
- SJ=1; //蜂鳴器報警
- buf[8]=buf[8]+0x10; //狀態字B3置1;
- }
- f=m-853; //853是電流10A的值,853=10/12*1024
- if(f>=0) //超出10A電流報警。
- {
- DJ=1; //發光二極管亮報警。
- SJ=1; //蜂鳴器報警
- buf[8]=buf[8]+0x08; //狀態字B3置1;
- }
- i=buf[8]&0x1f;
- if(i==0)
- {
- DJ=0; //發光二極管停止報警
- SJ=0; //蜂鳴器停止報警
- }
-
- }
- void test_T( uint m )
- {
- int f;
- uchar i;
- bufint[20]=m; //bufint[20]是溫度的16進制值。
- buf[8]=buf[8]&0xfb; //溫度正常,buf[8]是狀態字,狀態字的B2置0.
- f=m-700; //700是70度溫度f值大于70度是高溫狀態。
- if(f>0)
- {
- DJ=1; //發光二極管亮報警。
- SJ=1; //蜂鳴器報警。
- buf[8]=buf[8]+0x04; //狀態字B2置1。
- }
- i=buf[8]&0x1f;
- if(i==0)
- {
- DJ=0; //發光二極管停止報警
- SJ=0; //蜂鳴器停止報警
- }
- }
- void dsp_data_v( )
- {
- uchar i,a;
- uint k,m,j;
- a=0;
- j=0;
- k=0; //buf[35]、buf[36]是電壓的采樣值。
- i=buf[35]; //采樣電壓高位值送i
- k=(int)i;
- k<<=2; //高位置送字的高8位
- i=buf[36]; //采樣電壓低二位采樣值送i
- i=i&0x03;
- k=k+(int)i; //拼接為字
- m=k*5.8594; //電壓值乘以5.8594,600V電壓對應5V直流取樣電壓1024個單位,顯示放大10倍,默認最后一位為小數位。
- test_v(m);
- a=3; //buf[4]、buf[5]是電壓的BCD碼
- bcdzhuanhua(m,a);
- }
- void dsp_data_I( )
- {
- uchar i,a;
- uint k,m,j;
- a=0;
- j=0;
- k=0; //buf[37]、buf[38]是電流的采樣值?
- i=buf[37]; //采樣電流高位值送i
- k=(int)i;
- k<<=2; //高位置送字的高8位
- i=buf[38]; //采樣電流低二位采樣值送i
- i=i&0x03;
- k=k+(int)i; //拼接為字
- m=k*0.1171875; //電流值乘以0.1171875,12A電流對應5V直流取樣電壓,對應xxx.x的BCD4位碼,顯示放大10倍,默認最后一位為小數位。
- test_I(k);
- a=5; //buf[6]、buf[7]是電流的BCD碼
- bcdzhuanhua(m,a);
- }
- void dsp_data_T( )
- {
- uchar i,a;
- uint k,m,j;
- a=0;
- j=0;
- k=0; //buf[39]、buf[40]是溫度的采樣值。
- i=buf[39]; //采樣電流高位值送i
- k=(int)i;
- k<<=2; //高位置送字的高8位
- i=buf[40]; //采樣電流低二位采樣值送i
- i=i&0x03;
- k=k+(int)i; //拼接為字
- m=k*0.976525; //溫度值乘以0.976525,100度溫度對應5V直流取樣電壓,對應xxx.x的BCD4位碼,如065.7度、105.6度。
- test_T(m);
- a=8; //buf[9]、buf[10]是溫度的BCD碼。
- bcdzhuanhua(m,a);
- }
-
- void send1(uchar idata *d,uchar n) //發送函數
- { uchar i;
- REN=0; //防止自發自收。
- for (i=0;i<=n;i++)
- {
- TI=0;
- SBUF=d[i]; //發一個現在的數據
- while (TI==0);
- TI=0; //等待發送出去
- if(i==11)
- {
- TS=!TS;
- } //發送一次數據取反一次。
- }
- REN=1;
- }
-
- void receive(uchar idata *d,uchar n) //接受函數接收14位身份加2位開關
- {
- uchar i;
- for(i=0;i<=n;i++)
- {while (RI==0)
- {
- if(buf[25]>=0x07)
- {
- i=12; //接收的數據不可用,SBUF的數據儲存到d[24]中丟棄。
- break;
- }
- }
- RI=0; //接收n個數據;一般為12個。
- d[i+12]=SBUF; //接收一個數據,放在 d[i+m]處
- }
- }
-
-
- void main()
-
- {
- //buf[0]~buf[3]是報頭,buf[4]、buf[5]是輸出電壓BCD碼uf[6]、buf[7]是輸出電流BCD碼,buf[8]是輸出狀態標志1,
- //buf[9]、buf[10]是溫度BCD碼,buf[11]是輸入狀態標志2,
- buf[0]=0x1c; buf[1]=0xff; buf[2]=0x50; buf[3]=0xe7; buf[4]=0x00;
- buf[5]=zifu1[5]; buf[6]=zifu1[6]; buf[7]=zifu1[7]; buf[8]=0x00; buf[9]=zifu1[9];
- buf[10]=zifu1[10]; buf[11]=0x00; buf[12]=0x00; buf[13]=zifu1[13]; buf[14]=zifu1[14];
- buf[15]=zifu1[15]; buf[16]=zifu1[16]; buf[17]=zifu1[17]; buf[18]=zifu1[18]; buf[19]=zifu1[19];
- buf[20]=zifu1[20]; buf[21]=zifu1[21]; buf[22]=zifu1[22]; buf[23]=zifu1[23];
- bufint[23]=1222;
- // buf[39]=zifu1[24];
- //buf[25]=zifu1[25]; buf[26]=zifu1[26]; buf[27]=zifu1[27]; buf[28]=zifu1[28]; buf[29]=zifu1[29];
- //buf[30]=zifu1[30]; buf[31]=zifu1[31]; buf[32]=zifu1[32];
- time0Init(); //定時器0初始化
- inituart(); //串行口初始化 定時器2初始化//
- P1=0x00;
- P2=0x00;
- P3=0x80;
- for(; ;) //主程序循環執行。
- {
- uchar n,k;
- set_p1_adc_channel(); //AD采樣初始化
- if (buf[25]>0x09) //100ms時間值0x0a。
- {
- buf[34]= buf[34]+1; //記錄100ms時間的次數
- buf[25]=0; //buf[25]記錄10ms一次的時間,100ms時間到清零。其值為:
- n=35; //a/d的數據存放:buf[35]buf[36]電壓、buf[37]buf[38]電流、buf[39]buf[40]溫度。
- adcyang(buf,n); //A/D采樣。
- dsp_data_v( ); //對電壓值進行處理
- dsp_data_I( ); //對電流值進行處理
- dsp_data_T( ); //對溫度值進行處理
- }
- if (buf[34]>0x04) //500ms時間到,發送一次數據。
- {
- buf[34]=0; //發送完數據清零buf[34],500ms清零。
- k=11; //一共發送12個數據,從d[0]~d[11]。
- send1(buf,k);
- }
- n=11; //接收數據一幀為12個數據
- receive(buf,n);
- WDT_CONTR=0x34;
- n=1;
- delay(n);
- }
- }
- //2017年編制的電壓電流溫度測量軟件,處理并發送數據。
復制代碼
所有資料51hei提供下載:
備份.zip
(8.27 KB, 下載次數: 9)
2019-4-24 09:08 上傳
點擊文件名下載附件
單片機程序
|