标题:
单片机采样送can格式数据的源程序
[打印本页]
作者:
wl19900429
时间:
2019-4-24 09:09
标题:
单片机采样送can格式数据的源程序
单片机采样送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 上传
点击文件名下载附件
单片机程序
下载积分: 黑币 -5
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1