找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2524|回复: 3
收起左侧

STM32在线水质氨氮检测仪变送器开发PCB和单片机源程序

[复制链接]
ID:571920 发表于 2019-6-25 17:06 | 显示全部楼层 |阅读模式
开发的氨氮检测仪,采用CAN总线输出,源程序和PCB见附件:
技术参数如下:
技术参数
量程:0~100ppm(量程可调)
精度:0.1ppm
输出信号:CAN总线
传输协议:Modbus RTU
485波特率:9600(默认)
CAN频率:500K(默认)
温度范围:0-80
温度补偿:自动补偿
校准:命令方式(软件校准)
工作电压:5V/12V
电缆长度:标配5

Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
QQ截图20190625170137.jpg 0.png 0.png QQ截图20190625170348.jpg

单片机源程序如下:
  1. #include "led.h"
  2. #include "delay.h"
  3. #include "sys.h"
  4. #include "usart.h"
  5. #include "adc.h"
  6. #include "dma.h"
  7. #include "can.h"
  8. #include "rs485.h"
  9. #include "math.h"
  10. #include "stmflash.h"   

  11. //要写入到STM32 FLASH的字符串数组
  12. u16 flash[10],read[10];//第一位判断是否是初始设置
  13. #define SIZE sizeof(write)                 //数组长度
  14. #define FLASH_SAVE_ADDR  0X08040000         //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
  15. u16 get[20000];
  16. float n,m;
  17. int a,phase,crc,rsp;
  18. int array[]={115200,57600,38400,28800,19200,14400,9600,4800,2400,1200};
  19. u16 brq;

  20. int main(void)
  21. {
  22.          u8 rs485[8],send485[8],len;
  23.          u8 cnt=0;
  24.          u8 canbuf[8],canget[8];
  25.          int i;
  26.         float temp,nh;
  27.         delay_init();           
  28.         uart_init(9600);                 //串口初始化为9600
  29.         LED_Init();
  30.         if(flash[0]==10)RS485_Init(array[flash[4]]);
  31.         else                RS485_Init(9600);        //初始化RS485
  32.         MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)get,1904);//DMA1通道1,外设为串口1,存储器为SendBuff,长度应为转换通道数×转换次数
  33.         //采样952个点,50hz信号 20ms一周期,采样952个点 约为21us采样一次,即12Mhz频率 239.5+12.5个周期252 252=12*21
  34.         Adc_Init();               
  35.   DMA_Cmd(DMA1_Channel1, ENABLE);  //使能ADC DMA1 所指示的通道         
  36.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
  37.   STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)flash,10);
  38.   if(flash[0]==10)CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,flash[3],CAN_Mode_Normal);
  39.   else         
  40.         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
  41.         while(1)
  42.         {
  43.                
  44. //                while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);作为保留 防止第一位数据丢失
  45.                 //MYDMA_Enable(DMA1_Channel1);
  46.     LED1=!LED1;        
  47.         for(a=0;a<100;a++) //电压值求均值,叠加100次再除以100
  48.                 {
  49.         for(i=0;i<1902;i+=2)
  50.                 {
  51.                  n+=get[i]*get[i];
  52.                 }
  53.                 n=sqrt(n/952);
  54.                 nh+=n*(3.3/4096);
  55.                 n=0;
  56.                 }
  57.                 printf("nh4 is %f\r\n",nh/100);
  58.                 if(nh<51.3)
  59.           temp=1.01*nh-41.814;
  60.                 else temp=12*nh-614;
  61.                 printf("nh4 is %f\r\n",temp);
  62.                 nh=0;
  63. //                for(i=1;i<11;i+=2)
  64. //                {
  65. //                 printf("wendu is %f\r\n",(float)get[i]*(3.3/4096));
  66. //                 m+=get[i]*get[i];
  67. //                }
  68. //                        m=sqrt(m/952);
  69. //                printf("wendu is %f\r\n",(float)(m/100)*(3.3/4096));
  70. //                m=0;
  71.                  canbuf[2]=temp;        
  72.                  temp-=canbuf[2];
  73.                  temp*=100;
  74.                  canbuf[3]=temp;
  75.                  LED0=!LED0;
  76.                 RS485_Receive_Data(rs485,&len);
  77.                 if (rs485[0]==0xad)
  78.     {
  79.                         switch (rs485[1])
  80.                         {
  81.                                 
  82.                         case 0x02: //设置485频率
  83.                                  send485[0]=0xad;
  84.                            send485[1]=0x02;
  85.                                  rsp=(int)rs485[3];
  86.                                  if(rsp<0&&rsp>9) {send485[2]=0x11;        //如频率设置错误则返回错误代码 0xad 0x11 0x11 0x11 0x65 0xa7
  87.                                  send485[3]=0x11;
  88.                                  crc=CRC16_2(send485,4);
  89.                                  send485[4]=(unsigned char)(crc&0xff);
  90.          send485[5]=(unsigned char)((crc&0xff00)>>8);
  91.                            RS485_Send_Data(send485,6); }
  92.                                  else{RS485_Init(array[rsp]);
  93.                                  flash[1]=10;
  94.                                  flash[4]=rsp;
  95.                      //设置成功 返回 0xad 0x02 0x00 0x00 0x57 0x91
  96.                                  send485[2]=0x00;
  97.                                  send485[3]=0x00;
  98.                                  crc=CRC16_2(send485,4);
  99.                                  send485[4]=(unsigned char)(crc&0xff);
  100.          send485[5]=(unsigned char)((crc&0xff00)>>8);
  101.                            RS485_Send_Data(send485,6);}
  102.                                  break;
  103.                         case 0x03:   //查询NH4值
  104.                                  send485[0]=0xad;
  105.                            send485[1]=0x03;
  106.                            crc=CRC16_2(send485,4);
  107.                            send485[4]=(unsigned char)(crc&0xff);
  108.          send485[5]=(unsigned char)((crc&0xff00)>>8);
  109.                           RS485_Send_Data(send485,6);
  110.                            break;
  111.                         case 0x04:  //校准斜率
  112.                                  switch(canget[2])
  113.                                  {
  114.                                  case 0x00:
  115.                                          
  116.          send485[0]=0xad;
  117.          send485[1]=0x04;
  118.          crc=CRC16_2(send485,4);
  119.                            send485[4]=(unsigned char)(crc&0xff);
  120.          send485[5]=(unsigned char)((crc&0xff00)>>8);
  121.                            RS485_Send_Data(send485,6);
  122.          }
  123.                          }
  124.                          }                                 
  125.     Can_Receive_Msg(canget);
  126.     if (canget[0]==0xad)
  127.     {
  128.                         switch (canget[1])
  129.                         {
  130.                                 
  131.                         case 0x02: //设置can频率
  132.                                  canbuf[0]=0xad;
  133.                            canbuf[1]=0x02;
  134.                                  phase=(int)canget[3]+(int)(256*canget[2]);
  135.                                  if(2000%phase!=0) {canbuf[2]=0x11;        //如频率设置错误则返回错误代码 0xad 0x11 0x11 0x11 0x65 0xa7
  136.                                  canbuf[3]=0x11;
  137.                                  crc=CRC16_2(canbuf,4);
  138.                                  canbuf[4]=(unsigned char)(crc&0xff);
  139.          canbuf[5]=(unsigned char)((crc&0xff00)>>8);
  140.                            Can_Send_Msg(canbuf,6); }
  141.                                  else{brq=(u16)(2000/phase);
  142.                                  flash[0]=10;
  143.                                  flash[3]=brq;
  144.                                  STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)flash,10);
  145.                      CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,brq,CAN_Mode_Normal);//设置成功 返回 0xad 0x02 0x00 0x00 0x57 0x91
  146.                                  canbuf[2]=0x00;
  147.                                  canbuf[3]=0x00;
  148.                                  crc=CRC16_2(canbuf,4);
  149.                                  canbuf[4]=(unsigned char)(crc&0xff);
  150.          canbuf[5]=(unsigned char)((crc&0xff00)>>8);
  151.                            Can_Send_Msg(canbuf,6);}
  152.                                  break;
  153.                         case 0x03:   //查询NH4值
  154.                                  canbuf[0]=0xad;
  155.                            canbuf[1]=0x03;
  156.                            crc=CRC16_2(canbuf,4);
  157.                            canbuf[4]=(unsigned char)(crc&0xff);
  158.          canbuf[5]=(unsigned char)((crc&0xff00)>>8);
  159.                            Can_Send_Msg(canbuf,6);
  160.                            break;
  161.                         case 0x04:  //校准斜率
  162.                                  switch(canget[2])
  163.                                  {
  164.                                  case 0x00:
  165.                                          
  166.          canbuf[0]=0xad;
  167.          canbuf[1]=0x04;
  168.          crc=CRC16_2(canbuf,4);
  169.                            canbuf[4]=(unsigned char)(crc&0xff);
  170.          canbuf[5]=(unsigned char)((crc&0xff00)>>8);
  171.                            Can_Send_Msg(canbuf,6);
  172.          }                                         
  173.                         }
  174.                 }        
  175.     delay_ms(250);
  176.      
  177.         }                                                                                            
  178. }        
复制代码

所有资料51hei提供下载:
硬件.rar (626.83 KB, 下载次数: 69)

评分

参与人数 2黑币 +62 收起 理由
6789364 + 12 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:453576 发表于 2019-9-5 09:32 | 显示全部楼层
好东西,感谢楼主,健康永远是风口
回复

使用道具 举报

ID:453576 发表于 2019-9-5 09:32 | 显示全部楼层
感谢楼主!
回复

使用道具 举报

ID:728564 发表于 2020-4-13 21:30 | 显示全部楼层
真的很好。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表