作为一名使用PIC单片机近三十年的工程师,我最早从PIC16F87X系列起步,逐步深入至更集成、功能更丰富的型号。在智慧农业、工业控制等实际项目中,PIC32MX 是我频繁使用的核心芯片。其丰富的外设与六串口设计,非常适合构建多通道通信与控制系统。本次我将以一款实际投产数年的核心控制板为例,控制板MCU型号为PIC32MX534F064H,详解其串口与4G模块(移远EC800K)数据交互。
该控制板集成了以下6大功能:
1、2路RS485数据收发(可接LED屏、各种传感器、或与其他控制板通信);
2、1路UART-TTL(可接摄像头等);
3、1路4G模块数据收发(移远或中移4G模块);
4、1路LORA无线数据收发或RS485数据收发;
5、2路无源开关量输入;
6、太阳能供电(带充电管理)或直流电源直接供电;
一、硬件电路: PIC32MX534F064H与EC800K
PIC32MX534F064H具备六个独立UART模块,本设计中:
- UART2 通过电平转换电路连接4G模块,实现无线远程通信。
- 1、电源电路

- EC800K 电源供电要求3.4-4.3 V,需要确保输入电压不低于 3.4 V。所以使用了MP1584与HT7333的组合,MP1584输入范围4.5-28V,输出调节到3.96V给EC800K供电,由HT7333再输出稳定的3.3V,给单片机及相关外设供电,具体可参考我的另一篇文章《电源设计实战:深度解析 MP1584 与 HT7333 高效稳定电源方案》
- 2、UART2 与 EC800K 串口的电平匹配电路

- EC800K串口电平是1.8V,而单片机串口电平是3.3V,所以用了上图的电平转换电路。
二、 EC800K 数据透传简介:
以TCP客户端在透传模式下工作为例讲解一下EC800K的最简配置
下面第"三"的例程串口1和2的数据可以双向透传,串口1做RS485使用,可以接在电脑上通过串口助手软件测试EC800K如何进入TCP透传。
控制板上电后,以下三步测试命令可以让EC800K进入透传模式:
- 输入"AT"命令,返回"OK",说明单片机与EC800K连接成功;
- 输入" AT+QIACT=1"命令,返回"OK",说明场景激活成功,就是挂网成功,受网络状态影响,最大响应时间为 150 秒,超过150秒无响应或返回"ERROR",可以在程序里重启模块,设定几次不成功就退出;
- 输入" AT+QIOPEN=1,0,"TCP","220.180.239.212",8009,0,2"命令,返回"CONNECT",说明进入TCP透传模式,"220.180.239.212"是域名,8009是端口,根据实际输入;受网络状态影响,最大响应时间为 150 秒,超过150秒无响应或返回"ERROR",可以在程序里重启模块,设定几次不成功就退出;
注:在透传模式下AT指令无效,只能当作数据传输,需要输入"+++"退出透传才可以使用AT指令。
三、串口与 4G 通信例程:
以下是串口2与4G模块通信设置示例(80M主频),串口2波特率115200, 8N1格式,具体配置及程序如下:
#include<p32mx534f064h.h>
#pragma config FPLLMUL=MUL_20,FPLLIDIV=DIV_2,FPLLODIV=DIV_1,FWDTEN=OFF
#pragma config POSCMOD=HS,FNOSC=PRIPLL,FPBDIV=DIV_1
#define SYS_FREQ (80000000L)
unsigned char dres_485=1, flag_rev=0,flag_rev2=0,flag_rev3,flag_rev4,flag_rev5,flag_rev6;
unsigned int time_tnt,time_tnt2,time_tnt3,time_tnt4,time_tnt5,time_tnt6, ,rev_rnt=0,rev_rnt2=0,rev_rnt3,rev_rnt4,rev_rnt5,rev_rnt6,tran_rnt1=0,tran_rnt2=0,tran_rnt3,tran_rnt4,tran_rnt5,tran_rnt6;
unsigned char trans[200];
unsigned char reciv[200];
unsigned char trans2[200];
unsigned char reciv2[200];
unsigned char trans3[200];
unsigned char reciv3[200];
unsigned char trans4[200];
unsigned char reciv4[200];
unsigned char trans5[200];
unsigned char reciv5[200];
unsigned char trans6[200];
unsigned char reciv6[200];
void delay(unsigned int a)
{
int i,j;
for(i=0;i<a;i++)
for(j=0;j<100;j++)
;
}
void uart_send1(unsigned char dat) //串口1发送数据
{
U1STAbits.UTXEN=1;
U1TXREG=dat;
while(!U1STAbits.TRMT);
}
void uart_send2(unsigned char dat) //串口2发送数据
{
U2STAbits.UTXEN=1;
U2TXREG=dat;
while(!U2STAbits.TRMT);
}
void main() {
unsigned int i,j;
AD1PCFG=0XFFFF;
TRISB=0x0180;
PORTB=0x0000;
TRISC=0;
PORTC=0x0000;
TRISD=0x0204;
PORTD=0x0000;
TRISE=0x0000;
PORTE=0x0000;
TRISF=0x0010;
PORTF=0x0000;
TRISG=0x0280;
PORTG=0x0000;
DDPCON = 0x00 ; //关闭EJTAG口,
OSCCON&=0xfffd;
SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_5 | T1_INT_SUB_PRIOR_1);
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
UARTSetLineControl(UART1, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTConfigure(UART1, UART_ENABLE_HIGH_SPEED|UART_ENABLE_PINS_TX_RX_ONLY);
UARTSetDataRate(UART1, SYS_FREQ,9600);
UARTSetFifoMode(UART1, UART_INTERRUPT_ON_RX_NOT_EMPTY);
ConfigIntUART1(UART_RX_INT_EN | UART_INT_PR6 | UART_INT_SUB_PR2);
EnableIntU1RX;
UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTConfigure(UART2, UART_ENABLE_HIGH_SPEED|UART_ENABLE_PINS_TX_RX_ONLY);
UARTSetDataRate(UART2, SYS_FREQ, 115200);
UARTSetFifoMode(UART2, UART_INTERRUPT_ON_RX_NOT_EMPTY);
ConfigIntUART2(UART_RX_INT_EN | UART_INT_PR6 | UART_INT_SUB_PR2);
EnableIntU2RX;
UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
//其他初始化
INTEnableInterrupts();
OpenTimer1(T1_ON | T1_PS_1_1 | T1_SOURCE_INT,4000); //分频设置为1
delay(10000);
while(1) {
// 主循环,可加入其他任务
//此处具体程序可参考我的另一篇文章《PIC单片机进阶实战(二):PIC16F1947串口与4G模块数据交互》
}
}
void __ISR(_UART1_VECTOR, IPL6SOFT) IntUart1Handler(void)
{
if (INTGetFlag(INT_SOURCE_UART_RX(UART1)))
{
reciv[rev_rnt]=UARTGetDataByte(UART1);
rev_rnt+=1;
time_tnt=0;
flag_rev=1;
}
INTClearFlag(INT_SOURCE_UART_RX(UART1));
}
void __ISR(_UART2_VECTOR, IPL6SOFT) IntUart2Handler(void)
{
if (INTGetFlag(INT_SOURCE_UART_RX(UART2)))
{
reciv2[rev_rnt2]=tmp2=UARTGetDataByte(UART2);
rev_rnt2+=1;
time_tnt2=0;
flag_rev2=1;
}
INTClearFlag(INT_SOURCE_UART_RX(UART2));
}
void __ISR(_TIMER_1_VECTOR, ipl5) _Timer1Handler(void)
{
// DisableIntT1;
if(flag_rev==1)
{
time_tnt+=1; //1570约为06ms
}
if(flag_rev2==1)
{
time_tnt2+=1; //1570约为06ms
}
INTClearFlag(INT_T1);//中断标志清零
// EnableIntT1;
}
四、本系列文章规划
本文是《PIC单片机高阶实战》系列的第四篇,后续将逐步展开以下内容:
|----|-------------------|-----------------|
| 序号 | 主题 | 内容概要 |
| 1 | 振荡器与定时器 | 时钟配置与定时中断 |
| 2 | UART 通信 | 串口配置、波特率转换、数据透传 |
| 3 | I/O 按键输入 | 电平变化中断 |
| 4 | 4G 模块数据收发 | AT指令控制、4G模块数据透传 |
| 5 | 数据存储 | 数据存储与读取 |
《 PIC 单片机入门实战》共 8 篇文章与《 PIC 单片机进阶实战》共 6 篇文章与《 PIC 单片机高阶实战》 5 篇内容来源于我自己画的电路原理图及程序,有对 PIC 单片机感兴趣想学习的朋友可以关注我,免费赠送资料(包括原理图、数据手册、各种例程等)。
有需要这款开发板的朋友也可以关注联系我。
后续干货不断,咱们一起在单片机的世界里,共同进步。