深圳市英锐恩科技有限公司:台湾麦肯单片机(Micon MDT单片机)亚太地区A级代理商
QLdsPIC3]CAN总线[C30+dsPIC30F6014A]
//实验目的:CAN总线接收+LCD1602显示
//软件规划:
// 1。通过CAN总线接收另一主机发送过来的温度采集数据
// 2。接收到的数据转换后送1602LCD显示。
// 3。CAN模块采用模块C1,11位标识符的标准数据侦
//硬件规划:
// 1。拨玛开关S7全置ON
// 2。跳线J18全部接通
// 3。LCD1602插到座子上
// 4。接通CAN总线线缆
#include //dsPIC30F6014标准头文件
_FOSC(0x0ffe5); //4倍频晶振,Failsafe 时钟关闭
_FWDT(WDT_OFF); //关闭看门狗定时器
_FBORPOR(PBOR_OFF & MCLR_EN); //掉电复位禁止,MCLR复位使能。
_FGS(CODE_PROT_OFF); //代码保护禁止
#define rs LATBbits.LATB4 //定义LCD控制位(注意这里只能用LATB寄存器,不能直接用PORTB寄存器)
#define rw LATBbits.LATB5
#define e LATBbits.LATB6
unsigned char __attribute__((address(0x904))) TZ; //转换后的温度值整数部分
unsigned char __attribute__((address(0x906))) TX; //转换后的温度值小数部分
unsigned int __attribute__((address(0x908))) wd; //转换后的温度值BCD码形式
unsigned char __attribute__((address(0x9a0))) loop; //LCD显示次数计数器
unsigned int buffer1; //定义CAN接收缓冲单元
unsigned int buffer2;
unsigned int buffer3;
unsigned int buffer4;
unsigned char __attribute__((address(0x930))) result[8]={0,0,0,'.',0,0,0,0};
unsigned long int i = 0;
//********************CAN模块初始化函数*************************
void initcan()
{
C1CTRLbits.REQOP = 0x4; /进入配置模式
while (C1CTRLbits.OPMODE!=0x4){} //确认进入配置模式
C1TX0CON = 0x0003; //发送0邮箱配置,高优先级
C1TX0SID = 0x0020; //发送0标准标识符,11位
C1TX0DLC = 0x01c0; //发送0数据长度,8字节
C1RX0CON = 0x0000; //接收0邮箱配置
C1RX0DLC = 0x0008; //接收0数据长度,8字节
C1RXF0SID = 0x0020; //接收滤波器0标准标识符,11位
C1RXM0SID = 0xffff; //接收屏蔽0标准标识符
C1CFG1bits.SJW=0; //SJW=1 x TQ
C1CFG1bits.BRP = 9; //125K
C1CFG2 = 0x03Ac; //SEG2PH=5;SEG1PH=6;PRSEG=4
C1CTRLbits.REQOP = 0x0; /进入正常模式
while (C1CTRLbits.OPMODE!=0x0){} //确认进入正常模式
return;
}
//****************延时函数**************************************
//延时函数(延时时间为(2+x)us)
void delay( char x)
{
unsigned char i;
for(i=0;i<x;i++);
}
//*****************写一个字节数据函数***************************
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void write(unsigned char x)
{
PORTD=x; //待显示数据送PORTD口
delay(98);
rs=1; //该字节数据为数据,而不是命令
delay(98);
rw=0; //此次操作为写,而不是读
delay(98);
e=0; //拉低使能信号
delay(98); //保持使能信号为低一段时间
e=1; //拉高使能信号,建立LCD操作所需要的上升沿
delay(98);
}
//******************LCD显示设置函数*****************************
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void lcd_enable()
{
delay(98);
rs=0; //该字节数据为命令,而不是数据
delay(98);
rw=0; //此次操作为写,而不是读
delay(98);
e=0; //拉低使能信号
delay(98); //保持使能信号为低一段时间
e=1; //拉高使能信号,建立LCD操作所需要的上升沿
delay(98);
}
//******************系统初始化函数******************************
void init()
{
TRISF=0X0000; //先设置18B20口方向为输出
TRISB=0X0000; //设置B口方向为输出
TRISD=0X0000; //设置D口方向为输出
IFS0bits.T1IF=0; //先清除定时器中断标志位
PR1=0XFFFF; //周期定最大
T1CON=0X0020; //分频比为1:64
INTCON1=0x0000;
INTCON2=0x0000; //关闭所有中断
}
//*******************LCD初始化函数*******************************
void lcd_init()
{
PORTD=0X1; //清除显示
lcd_enable();
PORTD=0X38; //8位2行5*7点阵
lcd_enable();
PORTD=0X0e; //显示开,光标开,闪烁
lcd_enable();
PORTD=0X06; //文字不动,光标右移
lcd_enable();
}
//*********************LCD显示函数*******************************
void display()
{
PORTD=0X84; //显示首地址
lcd_enable();
for(loop=0;loop<8;loop++) //共显示8位
{
write(result[loop]); //查表并送显示
delay(100); //插入一定延时
}
}
//******************启动温度转换函数*****************************
void get_temp()
{
int i;
result[0]=(TZ/100)+0x30; //整数百位
result[1]=((TZ%100)/10)+0X30; //整数十位
result[2]=((TZ%100)%10)+0X30; //整数部分个位
wd=0;
if (TX & 0x80) wd=wd+5000;
if (TX & 0x40) wd=wd+2500;
if (TX & 0x20) wd=wd+1250;
if (TX & 0x10) wd=wd+625; //以上4条指令把小数部分转换为BCD码形式
result[4]=(wd/1000)+0x30; //十分位
result[5]=((wd%1000)/100)+0x30; //百分位
result[6]=((wd%100)/10)+0x30; //千分位
result[7]=(wd%10)+0x30; //万分位
}
//**********************主函数***********************************
int main()
{
init(); //调用系统初始化函数
lcd_init(); //LCD初始化函数
initcan(); //调用CAN初始化函数
buffer1=buffer2=buffer3=buffer4=0;
while(1)
{
while(C1RX0CONbits.RXFUL==0); //等待接收到数据
buffer1 = C1RX0B1; //读取接收到的数据
buffer2 = C1RX0B2;
buffer3 = C1RX0B3;
buffer4 = C1RX0B4;
C1RX0CONbits.RXFUL = 0;
TZ=buffer1;
TX=buffer2;
get_temp(); //调用温度转换函数
display(); //调用结果显示函数
}
}