
/********************************************************************************************************
*********************************************************************************************************
*
* File                : RS485.c
* Hardware Environment:	easyPIC pro v2
* Build Environment   : MPLAB V8.66 + PIC32 V2.01
* Microcontroller     : PIC32MX795F512L
* Version             : V1.0
* By                  : JEFF
* DATE				  : 20150320
*
*(c) Copyright 2010-2018, Logifind Tech CO.,LTD
*http://www.logifind.com
*All Rights Reserved
*
*********************************************************************************************************
********************************************************************************************************/
//
// 实验描述：串口助手发送数据,接收16 Byte数据,RS485 发出16Byte数据
//           LED及数码管 显示缓冲区数据.
//
// 头 文 件：C:\Program Files\Microchip\MPLAB C32 Suite\pic32-libs\include\proc
//
// 配 置 位：菜单栏 -> Help -> Topics.. -> PIC32MX Config Setting 
//
// 波 特 率：9600  N 8 1 
//
// 注意事项：每次必须累积 16Byte 数据,单片机才回传数据
//
//-------------------------------------------------------------------------------

#include <plib.h>                    //调用通用头文件

//-------------------------------------------------------------------------------
// POSCMOD = XT, FNOSC = PRIPLL, FWDTEN = OFF
// PLLIDIV = DIV_2, PLLMUL = MUL_20
// PBDIV = 4 (default)
// Main clock = 4MHz /2 * 20    =  40MHz
// Peripheral clock = 40MHz /4  =  10MHz
// SYSCLK = 40 MHz (4MHz Crystal/FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK  = 10 MHz

#pragma config POSCMOD  = XT         //主振荡器  
#pragma config FNOSC    = PRIPLL     //倍频模式 
#pragma config FPLLIDIV = DIV_2      //输入分频 1:2
#pragma config FPLLMUL  = MUL_20     //PPL 倍频 1:20
#pragma config FPLLODIV = DIV_1      //输出分频 1:1
#pragma config FPBDIV   = DIV_4      //外设时钟
#pragma config FWDTEN   = OFF        //关闭看门狗
#pragma config ICESEL   = ICS_PGx1   //调试端口1

#define SysLED     _LATB5                       //CPU LED
#define SPEKAK     _LATD8                       //蜂呜器
#define RELAY      _LATD8                       //继电器
#define bctl_485   _LATB15                      //485控制端


#define Smg_a    0xFE                           //定义段码
#define Smg_b    0xFD
#define Smg_c    0xFB
#define Smg_d    0xF7
#define Smg_e    0xEF
#define Smg_f    0xDF
#define Smg_g    0xBF
#define Smg_dp   0x7F

#define Bmp0Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_e & Smg_f 
#define Bmp1Map          Smg_b & Smg_c
#define Bmp2Map          Smg_a & Smg_b & Smg_d & Smg_e & Smg_g
#define Bmp3Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_g
#define Bmp4Map          Smg_b & Smg_c & Smg_f & Smg_g
#define Bmp5Map          Smg_a & Smg_c & Smg_d & Smg_f & Smg_g
#define Bmp6Map          Smg_a & Smg_c & Smg_d & Smg_e & Smg_f & Smg_g
#define Bmp7Map          Smg_a & Smg_b & Smg_c 
#define Bmp8Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_e & Smg_f & Smg_g
#define Bmp9Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_f & Smg_g
#define BmpAMap          Smg_a & Smg_b & Smg_c & Smg_e & Smg_f & Smg_g
#define BmpBMap          Smg_c & Smg_d & Smg_e & Smg_f & Smg_g
#define BmpCMap          Smg_a & Smg_d & Smg_e & Smg_f 
#define BmpDMap          Smg_b & Smg_c & Smg_d & Smg_e & Smg_g
#define BmpEMap          Smg_a & Smg_d & Smg_e & Smg_f & Smg_g
#define BmpFMap          Smg_a & Smg_e & Smg_f & Smg_g




const unsigned char SegCode[] =                //显示段码表
{
	Bmp0Map,Bmp1Map,Bmp2Map,Bmp3Map,Bmp4Map,Bmp5Map,Bmp6Map,Bmp7Map,
	Bmp8Map,Bmp9Map,BmpAMap,BmpBMap,BmpCMap,BmpDMap,BmpEMap,BmpFMap
};

unsigned char DpyNum[6] = {Smg_g,Smg_g,Smg_g,Smg_g,Smg_g,Smg_g}; //显示缓冲区   

unsigned char RxBuffer[16] = {0,0,0,0};        //串口接收缓冲区
unsigned char SysTick = 0;                     //系统时基
unsigned char COM2_RecvCnt  = 0;               //计数清零
unsigned char COM2_RecvFlag = 0;               //接收标志
unsigned char COM2_SendDatCnt = 0;             //发送计数        
unsigned char COM2_SendDatLength = 0;          //发送长度

//-------------------------------------------------------------------------------
//  延时函数
//-------------------------------------------------------------------------------
void Delay_xmS(unsigned int i)                
{
	unsigned int j;
	for(;i>0;i--)
	{
		Nop();
		for(j=0;j<255;j++)
		{
			Nop();
			ClearWDT();
		}
	}	
}

//-------------------------------------------------------------------------------
//  串口2初始化函数
//-------------------------------------------------------------------------------
void UART2_Init(void)
{
	bctl_485 = 0;                    // 接收模式
	U2MODEbits.SIDL  = 0;            // IDLE工作
	U2MODEbits.IREN  = 0;            // 禁止IrDA
	U2MODEbits.UEN   = 0;            // 使能RX TX引脚
	U2MODEbits.WAKE  = 0;            // 禁止唤醒
	U2MODEbits.ABAUD = 0;            // 禁止自动BUD
	U2MODEbits.RXINV = 0;            // 空闲状态为1
	U2MODEbits.BRGH  = 0;            // 16x标准波特率
	U2MODEbits.PDSEL = 0;            // 8位无奇偶校验
	U2MODEbits.STSEL = 0;            // 1个停止位
	
	U2STAbits.ADM_EN   = 0;          // 关自动地址检测
	U2STAbits.UTXISEL1 = 0;          // 发送完所有字符后中断
	U2STAbits.UTXISEL0 = 1;
	U2STAbits.UTXINV   = 0;          // 空闲状态为1
	U2STAbits.URXEN    = 1;          // 接收器使能	
	
	U2STAbits.UTXBRK   = 0;          // 禁止发送间隔位
	U2STAbits.UTXEN    = 1;          // 发送器使能
	                                               
	U2STAbits.URXISEL1 = 0;          // 接收1个字符中断
	U2STAbits.URXISEL0 = 0;
	
	U2BRG = 64;                      // PBCLK 10MHz  N 8 1 9600 BRG = 64;
	
	IPC8bits.U2IP   = 4;             // 主优选级
	IPC8bits.U2IS   = 1;             // 次优选级
	
	IEC1bits.U2RXIE = 1;             // 接收中断
	IEC1bits.U2TXIE = 0;             // 发送中断
	
	U2MODEbits.ON   = 1;             // 串口使能 
}

//-------------------------------------------------------------------------------
//  串口2中断函数  注意中断编号
//-------------------------------------------------------------------------------
void __attribute__((vector(32)))__attribute__((interrupt(IPL4)))_UART2Interrupt(void)
{
	if(IFS1bits.U2RXIF == 1)              //接收中断  
	{	
		RxBuffer[COM2_RecvCnt++] = U2RXREG; //储存
		if(COM2_RecvCnt == 16)              //接收计数
		{
			COM2_RecvCnt = 0;
			COM2_RecvFlag = 1; 
		}
		IFS1bits.U2RXIF = 0;
	}

	if(IFS1bits.U2TXIF & IEC1bits.U2TXIE) //发送中断         
	{
		IFS1bits.U2TXIF = 0;              //清中断标志
		if(COM2_SendDatCnt != COM2_SendDatLength)  //发送未完成?
		{
			U2TXREG = RxBuffer[COM2_SendDatCnt++]; //装载数数据
		}
		else                              //发送完成
		{ 
			if(U2STAbits.TRMT == 1)       //移位寄存器空
			{
	    		bctl_485 = 0;             //接收模式
				IEC1bits.U2TXIE = 0;      //禁止中断
			}   
	    }
	}
}

//---------------------------------------------------------------------------------
//  TMR1初始化
//---------------------------------------------------------------------------------
void Timer1_Init(void)
{
	T1CON = 0;              // Timer1 清零
	
	IFS0bits.T1IF = 0;      // Timer1 清除标志位
	IEC0bits.T1IE = 1;      // Timer1 中断允许
	IPC1bits.T1IP = 4;      // Timer1 中断优选级
	IPC1bits.T1IS = 1;      // Timer1 次优选级
	TMR1=  0x0000;          // Timer1 给定初值
	PR1 = 0x9C3F;           // Timer1 周期寄存器
	
	T1CONbits.TON = 1;      // Timer1 启动计数
}

//---------------------------------------------------------------------------------
//  数码管驱动
//---------------------------------------------------------------------------------
void SegDisplay(void)
{
	static unsigned char step = 0;
	LATD = (LATD&0xFF00)|DpyNum[step];  //显示缓冲
	switch(step)                        //片选
	{
		case 0: _LATB8 = 0;_LATB9 = 1;_LATB10 = 1;_LATB11 = 1;_LATB12 = 1;_LATB13 = 1;break;
		case 1: _LATB8 = 1;_LATB9 = 0;_LATB10 = 1;_LATB11 = 1;_LATB12 = 1;_LATB13 = 1;break;
		case 2: _LATB8 = 1;_LATB9 = 1;_LATB10 = 0;_LATB11 = 1;_LATB12 = 1;_LATB13 = 1;break;
		case 3: _LATB8 = 1;_LATB9 = 1;_LATB10 = 1;_LATB11 = 0;_LATB12 = 1;_LATB13 = 1;break;
		case 4: _LATB8 = 1;_LATB9 = 1;_LATB10 = 1;_LATB11 = 1;_LATB12 = 0;_LATB13 = 1;break;
		case 5: _LATB8 = 1;_LATB9 = 1;_LATB10 = 1;_LATB11 = 1;_LATB12 = 1;_LATB13 = 0;break;
		default:break;
	}
	if(step < 5) step ++;         //扫描
	else      	 step = 0;
}
	
//---------------------------------------------------------------------------------
//  TMR1 中断函数
//---------------------------------------------------------------------------------
void __attribute__ ((vector(4)))__attribute__((interrupt(IPL4)))_T1Interrupt(void)
{	
	IFS0bits.T1IF = 0;
	SegDisplay();                 //数码管扫描
	SysTick = 1;                  //系统 Tick
}

//---------------------------------------------------------------------------------
//  主函数
//---------------------------------------------------------------------------------
int main(void)
{
	unsigned char temp = 0;       //临时变量
	unsigned char Delay = 0;      
	
	AD1PCFG = 0xFFFF;             //引脚为数字I/O
	TRISB  = 0x40DF;              //RB5 RB8-RB13输出
	TRISG  = 0xFFFF;              //G端口输出
	TRISE  = 0x0000;              //E端口输出
	TRISD  = 0xFE00;              //RD0-RD7 RD8 输出
	
	LATD = 0x00FF;                //关闭蜂呜器
	Timer1_Init();                //TMR1初始化
	UART2_Init();                 //UART初始化
	
	INTEnableSystemMultiVectoredInt(); //使能中断多向量表  
		
	LATE = 0x00FF;                //点亮 D0 - D7
	Delay_xmS(400);
	LATE = 0x0000;                //关闭 D0 - D7
	Delay_xmS(400);
	LATE = 0x00FF;                //点亮 D0 - D7
	Delay_xmS(400);
	LATE = 0x0000;                //关闭 D0 - D7
	Delay_xmS(200);

	while(1)
	{
		//----------------------LCD显示-------------------------
		if(COM2_RecvFlag == 1)
		{
			bctl_485 = 1;            //发送模式
			COM2_RecvFlag = 0;       //清标志
			COM2_SendDatCnt = 0;     //准备发送
	   		COM2_SendDatLength = 16; //数据长度
			IEC1bits.U2TXIE = 1;     //启动发送
		}
		if(SysTick == 1)             //系统显示延时
		{
			SysTick = 0;
			Delay ++;
		}	
		if(Delay > 120)              //刷新显示
		{
			Delay = 0;
		   	DpyNum[0] = SegCode[temp/10];             //LCD 分段       
			DpyNum[1] = SegCode[temp%10];
			DpyNum[2] = Smg_g;
			DpyNum[3] = Smg_g;
			DpyNum[4] = SegCode[RxBuffer[temp]>>4];   //显示接收数据高4位
			DpyNum[5] = SegCode[RxBuffer[temp]&0x0F]; //显示接收数据低4位
			
			LATE = RxBuffer[temp];                    //LED显示当前数据
			
			temp = (temp + 1)&0x0F;                   //循环显示
			SysLED = !SysLED;                         //CPU LED
		}
		
		//------------------------------------------------------
	}
}



//---------------------------------------------------------------------------------

