单片机采样送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)
|