开发的氨氮检测仪,采用CAN总线输出,源程序和PCB见附件:
技术参数如下:
技术参数 量程:0~100ppm(量程可调) 精度:0.1ppm 输出信号:CAN总线 传输协议:Modbus RTU 485波特率:9600(默认) CAN频率:500K(默认) 温度范围:0-80℃ 温度补偿:自动补偿 校准:命令方式(软件校准) 工作电压:5V/12V 电缆长度:标配5米
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
单片机源程序如下:
- #include "led.h"
- #include "delay.h"
- #include "sys.h"
- #include "usart.h"
- #include "adc.h"
- #include "dma.h"
- #include "can.h"
- #include "rs485.h"
- #include "math.h"
- #include "stmflash.h"
- //要写入到STM32 FLASH的字符串数组
- u16 flash[10],read[10];//第一位判断是否是初始设置
- #define SIZE sizeof(write) //数组长度
- #define FLASH_SAVE_ADDR 0X08040000 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
- u16 get[20000];
- float n,m;
- int a,phase,crc,rsp;
- int array[]={115200,57600,38400,28800,19200,14400,9600,4800,2400,1200};
- u16 brq;
- int main(void)
- {
- u8 rs485[8],send485[8],len;
- u8 cnt=0;
- u8 canbuf[8],canget[8];
- int i;
- float temp,nh;
- delay_init();
- uart_init(9600); //串口初始化为9600
- LED_Init();
- if(flash[0]==10)RS485_Init(array[flash[4]]);
- else RS485_Init(9600); //初始化RS485
- MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)get,1904);//DMA1通道1,外设为串口1,存储器为SendBuff,长度应为转换通道数×转换次数
- //采样952个点,50hz信号 20ms一周期,采样952个点 约为21us采样一次,即12Mhz频率 239.5+12.5个周期252 252=12*21
- Adc_Init();
- DMA_Cmd(DMA1_Channel1, ENABLE); //使能ADC DMA1 所指示的通道
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
- STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)flash,10);
- if(flash[0]==10)CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,flash[3],CAN_Mode_Normal);
- else
- CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_Normal);//36M/((8+9+1)*4)=500Kbps,brp可以设置从0~1024
- while(1)
- {
-
- // while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);作为保留 防止第一位数据丢失
- //MYDMA_Enable(DMA1_Channel1);
- LED1=!LED1;
- for(a=0;a<100;a++) //电压值求均值,叠加100次再除以100
- {
- for(i=0;i<1902;i+=2)
- {
- n+=get[i]*get[i];
- }
- n=sqrt(n/952);
- nh+=n*(3.3/4096);
- n=0;
- }
- printf("nh4 is %f\r\n",nh/100);
- if(nh<51.3)
- temp=1.01*nh-41.814;
- else temp=12*nh-614;
- printf("nh4 is %f\r\n",temp);
- nh=0;
- // for(i=1;i<11;i+=2)
- // {
- // printf("wendu is %f\r\n",(float)get[i]*(3.3/4096));
- // m+=get[i]*get[i];
- // }
- // m=sqrt(m/952);
- // printf("wendu is %f\r\n",(float)(m/100)*(3.3/4096));
- // m=0;
- canbuf[2]=temp;
- temp-=canbuf[2];
- temp*=100;
- canbuf[3]=temp;
- LED0=!LED0;
- RS485_Receive_Data(rs485,&len);
- if (rs485[0]==0xad)
- {
- switch (rs485[1])
- {
-
- case 0x02: //设置485频率
- send485[0]=0xad;
- send485[1]=0x02;
- rsp=(int)rs485[3];
- if(rsp<0&&rsp>9) {send485[2]=0x11; //如频率设置错误则返回错误代码 0xad 0x11 0x11 0x11 0x65 0xa7
- send485[3]=0x11;
- crc=CRC16_2(send485,4);
- send485[4]=(unsigned char)(crc&0xff);
- send485[5]=(unsigned char)((crc&0xff00)>>8);
- RS485_Send_Data(send485,6); }
- else{RS485_Init(array[rsp]);
- flash[1]=10;
- flash[4]=rsp;
- //设置成功 返回 0xad 0x02 0x00 0x00 0x57 0x91
- send485[2]=0x00;
- send485[3]=0x00;
- crc=CRC16_2(send485,4);
- send485[4]=(unsigned char)(crc&0xff);
- send485[5]=(unsigned char)((crc&0xff00)>>8);
- RS485_Send_Data(send485,6);}
- break;
- case 0x03: //查询NH4值
- send485[0]=0xad;
- send485[1]=0x03;
- crc=CRC16_2(send485,4);
- send485[4]=(unsigned char)(crc&0xff);
- send485[5]=(unsigned char)((crc&0xff00)>>8);
- RS485_Send_Data(send485,6);
- break;
- case 0x04: //校准斜率
- switch(canget[2])
- {
- case 0x00:
-
- send485[0]=0xad;
- send485[1]=0x04;
- crc=CRC16_2(send485,4);
- send485[4]=(unsigned char)(crc&0xff);
- send485[5]=(unsigned char)((crc&0xff00)>>8);
- RS485_Send_Data(send485,6);
- }
- }
- }
- Can_Receive_Msg(canget);
- if (canget[0]==0xad)
- {
- switch (canget[1])
- {
-
- case 0x02: //设置can频率
- canbuf[0]=0xad;
- canbuf[1]=0x02;
- phase=(int)canget[3]+(int)(256*canget[2]);
- if(2000%phase!=0) {canbuf[2]=0x11; //如频率设置错误则返回错误代码 0xad 0x11 0x11 0x11 0x65 0xa7
- canbuf[3]=0x11;
- crc=CRC16_2(canbuf,4);
- canbuf[4]=(unsigned char)(crc&0xff);
- canbuf[5]=(unsigned char)((crc&0xff00)>>8);
- Can_Send_Msg(canbuf,6); }
- else{brq=(u16)(2000/phase);
- flash[0]=10;
- flash[3]=brq;
- STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)flash,10);
- CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,brq,CAN_Mode_Normal);//设置成功 返回 0xad 0x02 0x00 0x00 0x57 0x91
- canbuf[2]=0x00;
- canbuf[3]=0x00;
- crc=CRC16_2(canbuf,4);
- canbuf[4]=(unsigned char)(crc&0xff);
- canbuf[5]=(unsigned char)((crc&0xff00)>>8);
- Can_Send_Msg(canbuf,6);}
- break;
- case 0x03: //查询NH4值
- canbuf[0]=0xad;
- canbuf[1]=0x03;
- crc=CRC16_2(canbuf,4);
- canbuf[4]=(unsigned char)(crc&0xff);
- canbuf[5]=(unsigned char)((crc&0xff00)>>8);
- Can_Send_Msg(canbuf,6);
- break;
- case 0x04: //校准斜率
- switch(canget[2])
- {
- case 0x00:
-
- canbuf[0]=0xad;
- canbuf[1]=0x04;
- crc=CRC16_2(canbuf,4);
- canbuf[4]=(unsigned char)(crc&0xff);
- canbuf[5]=(unsigned char)((crc&0xff00)>>8);
- Can_Send_Msg(canbuf,6);
- }
- }
- }
- delay_ms(250);
-
- }
- }
复制代码
所有资料51hei提供下载:
硬件.rar
(626.83 KB, 下载次数: 69)
软件.7z
(204.04 KB, 下载次数: 49)
|