在智慧农业、工业控制等实际项目中,PIC16F1947 成为我近年来高频使用的核心芯片。其丰富的外设与双串口设计,非常适合构建多通道通信与控制系统。本次我将以一款实际投产数年的控制板为例,详解I/O输入与继电器输出及直流电机正反转控制

该控制板集成了以下8大功能,覆盖多数物联网与工控场景:

16路继电器输出;

22DC24V12V直流电机正反转控制;

314G模块数据收发;

41LORA无线数据收发或RS485数据收发;

52路无源开关量输入;

61路电流互感器(5A/10A)数据采集;

71路数模转换(数字量转4-20mA/0-5V/0-10V;

81路模数转换(4-20mA/0-5V/0-10V转数字量)。

一、硬件电路:

上图是直流电机正反转电路,单片机I/O脚与ctl_xr和ctl_xf相连,RZ7899输出控制直流电机,也可以控制电磁阀;ctl_x高电平、ctl_xf3电平时电机正转,反之电机反转,都为低电平电机停止。

6路继电器输出和2路无源开关量输入(如按键输入)请参考我的PIC单片机入门实战(二)》和《PIC单片机入门实战(三)》。

二、例程:

以下是程序示例(16M主频),通过MODBUS协议的05功能码实现两路直流电机的正反转及停止,具体程序如下:

#include<pic16f1947.h>

__CONFIG(0x007c);  //内部时钟16M

__CONFIG(0x1010);  //内部时钟16M

unsigned char dres_485=1,txi,sec_5s=0,half_sec=0 ,flag_rev=0,flag_rev2=0,leijia_tnt2;
unsigned int  time_tnt,time_tnt2,sec_05s,rev_rnt=0,rev_rnt2=0,tran_rnt=0,tran_rnt2=0,sec_1s=0,crc_hl;   

unsigned char eeprom_e2[30]; //EEPROM缓存
unsigned long result_3421[30];
unsigned char trans[50];
unsigned char reciv[200]; //串口1接收缓存
unsigned char reciv2[200]; //串口2接收缓存

void delay(unsigned int v)
{
  while(v!=0)v--;
}
void uart_send(unsigned char dat) //串口1发送
{
               TX1STAbits.TXEN=1;
               TX1REG=dat;
               while(!TX1STAbits.TRMT);
}

void uart_send2(unsigned char datt) //串口2发送

{
               TX2STAbits.TXEN=1;
               TX2REG=datt;
               while(!TX2STAbits.TRMT);
}
void calccrc(uchar crcbuf)
{
               uchar i;
               crc_hl=crc_hl^crcbuf;
               for(i=0;i<8;i++)
               {
                               uchar TT;
                               TT=crc_hl&1;
                               crc_hl=crc_hl>>1;
                               crc_hl=crc_hl&0x7fff;
                               if(TT==1)
                               crc_hl=crc_hl^0xa001;
                               crc_hl=crc_hl&0xffff;
               }
}
void interrupt isr(void)
{             
               if(TMR1IF)
               {
                               TMR1L=0xbf;
                               TMR1H=0xf9;
                               sec_05s+=1;
                               sec_1s+=1;
                               if(sec_05s>624) //0.5s
                               {
                                              half_sec+=1;
                                              sec_5s+=1;
                                              
                                              

                                              sec_05s=0;
                               }
                               
                               if(flag_rev==1)
                               {
                                              time_tnt+=1;  //1570约为06ms
                               }
                               if(flag_rev2==1)
                               {
                                              time_tnt2+=1;  //1570约为06ms
                               } 
                               TMR1IF=0;
                               
               
               } 
               
               if(RCIF)
               {
                               reciv[rev_rnt]=RC1REG;
                               rev_rnt+=1;
                               time_tnt=0;
                               flag_rev=1;
               
                               RCIF=0;
                               
                               
               }
               if(RC2IF)
               {
                               reciv2[rev_rnt2]=RC2REG;
                               rev_rnt2+=1;
                               time_tnt2=0;
                               flag_rev2=1;
                               
                               RC2IF=0;
                               
                               
               }

}
void main()
{
               unsigned int i,j; 
               unsigned char tmp;
               ANSELF=0;
               ANSELG=0;
//             ADCON0=0;
               TRISC=0x80;
               TRISB=0x87;
               OPTION_REG&=0X7F;
               WPUB7=1;
               TRISD=0x00;
               TRISE=0x00;
               TRISF=0x00;
               
               TRISG=0x0c;
//             TRISG=0x00;

               PORTC=0x38;
               PORTD=0x00;
               PORTE=0x00;
               PORTF=0x00;
               PORTG=0x00;
//             OSCCON=0x0;
               OSCSTAT=0xa0;
               OSCCON=0x78; //内部时钟16M
//             OSCCON=0xf0; //32M
//             OSCSTAT=0xf0;//32M
               PIE1=0x21;
               INTCON=0x00;
               T1CON=0x70;
               TMR1IF=0;
               TMR1L=0xbf; //0.8ms
               TMR1H=0xf9;
               TMR1IE=1;
               T1CON=0x71; 

//             SYNC=0;                                             //异步模式
//             BRGH=1;                                            //加速
               TX1STA=0x24;  //8 n 1
               RC1STA=0x90;
//             BRG16=1;
               BAUD1CON=0x08;
               
//             SPEN=1;                                              //允许串行通讯
//             TXEN=1;
//             CREN=1;
               RCIF=0;
               RCIE=1;

//             SP1BRGL=0xa0;  //9600  //16MHZ
//             SP1BRGH=0x01;
               SP1BRGL=0x22;  //115200  //16MHZ
               SP1BRGH=0x00;

               RC2IF=0;
               RC2STA=0x90;  //8 n 1
               TX2STA=0x24;
//             RC2STA=0xd0;  //8 n 2
//             TX2STA=0x64;
//             BRG16=1;
               BAUD2CON=0x08;
               RC2IE=1;

               SP2BRGH=0x01; 
               SP2BRGL=0xa0;  //9600 //16MHZ
PEIE=1;
GIE=1;
while(1)
               {
                               asm("clrwdt");
                               
                               
                               
                               if((flag_rev==1)&&(time_tnt>7))  //time_tnt=125约为10ms

                               {
           //可在此加入“AT”、AT+QIACT=1”、AT+QIOPEN=1,0,"TCP","220.180.239.212",8009,0,2”等命令及判断是否进入透传模式
            
                                                             rev_rnt=0;
                                                             time_tnt=0;
                                                             flag_rev=0;
                                              
                               }

                               if((flag_rev2==1)&&(time_tnt2>5))

                               {
                                              if(rev_rnt2==8)
                                            {
                                              crc_hl=0xffff;
                                              for(txi=0;txi<6;txi++)
                                              {
                                                             calccrc(reciv2[txi]);
                                                             }
                                            if((reciv2[0]==dres_485)&&(reciv2[1]==0x05)&&(reciv2[6]==(crc_hl&0xff))&&(reciv2[7]==(crc_hl>>8))) //开关各继电器
                                              {
                                                             
                                                             if(reciv2[3]==8)   //1#电机正转
                                                             {
                                                                            if(reciv2[4]==0) //
                                                                            {
                                                                                            RF0=0;
                                                                                            RF1=0;
                                                                                            //flag_dianji_on&=0xfe;
                                                                            }
                                                                            else if(reciv2[4]==0xff) //启动
                                                                             {
                                                                                            
                                                                                            RF0=1;   
                                                                                            RF1=0;
                                                                                            //flag_dianji_on|=0x01;
                                                                            }
                                                             }
                                                             if(reciv2[3]==9) //1#电机反转
                                                             {
                                                                            if(reciv2[4]==0) //
                                                                            {
                                                                                            RF0=0;
                                                                                            RF1=0;
                                                                                            //flag_dianji_on&=0xfd;
                                                                            }
                                                                            else if(reciv2[4]==0xff) //启动
                                                                            {
                                                                                            
                                                                                            RF0=0;   
                                                                                            RF1=1;
                                                                                            //flag_dianji_on|=0x02;
                                                                            }
                                                             }
                                                             if(reciv2[3]==10)   //2#电机正转
                                                             {
                                                                            if(reciv2[4]==0) //
                                                                            {
                                                                                            RF2=0;
                                                                                            RF3=0;
                                                                                            //flag_dianji_on&=0xfb;
                                                                            }
                                                                            else if(reciv2[4]==0xff) //启动
                                                                            {
                                                                                            
                                                                                            RF2=1;   
                                                                                            RF3=0;
                                                                                            //flag_dianji_on|=0x04;
                                                                            }
                                                             }
                                                             if(reciv2[3]==11) //2#电机反转
                                                             {
                                                                            if(reciv2[4]==0) //
                                                                            {
                                                                                            RF2=0;
                                                                                            RF3=0;
                                                                                            //flag_dianji_on&=0xf7;
                                                                            }
                                                                            else if(reciv2[4]==0xff) //启动
                                                                            {
                                                                                            
                                                                                            RF2=0;   
                                                                                            RF3=1;
                                                                                            //flag_dianji_on|=0x08;
                                                                            }
                                                             }
                                                              
                                                             
                                                             }
                                            
                                          PORTG|=0X0001;
                                              for(i=0;i<8;i++)
                                                             {
                                                                            uart_send2(reciv2[i]); //数据回传
                                                             
                                                             }
                                                             PORTG&=0XFFFE;
                                              }
                                              
                                              rev_rnt2=0;
                                              time_tnt2=0;
                                              flag_rev2=0;
                               }
                               
               }
}
三、本系列文章规划

PIC单片机进阶实战》系列共六篇,后续将逐步展开以下内容:

序号

主题

内容概要

1

UART通信

双串口配置、波特率转换、数据透传

2

4G模块数据收发

AT指令控制、4G模块数据透传

3

电流互感器数据采集

5A10A电流采集

4

数模转换

12位模拟量输出4-20mA/0-5V/0-10V

5

输入输出

开关量输入、控制继电器与直流电机

6

模数转换

4-20mA/0-5V/0-10V模拟量采集

附:《PIC单片机入门实战》共8篇文章与《PIC单片机进阶实战》共6篇文章内容来源于我自己画的电路原理图及程序,有对PIC单片机感兴趣想学习的朋友可以关注我,免费赠送资料(包括原理图、数据手册、各种例程等)。

有需要这两款控制板的朋友也可以关注联系我。

后续干货不断,咱们一起在单片机的世界里,共同进步。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐