准备用PIC18F458芯片在CCS编译器下开始CAN总线的学习,在开始之前首先找来了官方的例程,对照看下。
看英文头大,翻译成中文注释,看着舒服些。
安装完CCS后,原文件位置...\PICC\Examples\ex_can_ccs_a.c
///
EX_CAN_CCS_A.C例子使用CCS的CAN库函数, 可以用于 PIC18Fxx8, PIC24 或者dsPIC33.
此示例进行了测试 使用 CCS读写CAN原型板 CAN Bus 和CAN Bus 24.
CCS原型电路板有四个相互连接的CAN节点
节点 A 是一个 18F458, CAN Bus, 或者24HJ256GP7610, CAN Bus 24, 使用内部CAN及外围设备.
节点 B 是一个 PIC16F87x, CAN Bus, 或者 30F4011, CAN Bus 24,连接到一个额外的 MCP2510 CAN
外围设备, 然而节点 C 和节点 D 都是 MCP250xx 独立CAN I / O扩展器.
这个例子是节点A的固件每两秒钟,这的固件发出了一个命令到节点B
去改变节点B leds (CAN ID 0x202) 的状态
通过A/D读取值得变化, 一个 0-9的数值被送到
节点 D 将此数值显示在一个 8段 LCD数码管上 (CAN ID 0x400)
通过按下节点A 中的按钮, 向节点B发送一个请求 (CAN ID 0x201) 通过读节点B中 A/D 的数值,
节点B将通过CAN把读来的A/d数值发出(with CAN ID 0x201).
同时, 按下节点A 中的按钮将会改变节点C中LED灯的状态(CAN ID 0x300)按节点C中的按钮会导致节点A的按钮发生改变
(节点 C 发送按钮变化 CAN ID 0x303)
使用串行端口,您可以检查所有 CAN 通讯 比如:观察18xxx8 或者 PIC24HJ.
想要了解在CCS上更多的CAN库文件, 可以看到 can-18xxx8.c 和 can-PIC24.c
这个例子只可以工作在PCH 和 PCD 编译器
官方例程,羊兄台翻译
///
连接CCS CAN原型板时的波特率设置
板频率 20Mhz:
PIC18Fxx8 设备
Baud Rate Prescalar: 4 //波特率预分频
Propagation Segment: 3xTq //传播段
Phase Segment 1: 6xTq //相位缓冲段1
Phase Segment 2: 6xTq //相位缓冲段2
Synchronized Jump Width: 1xTq //同步跳转宽度
Sample Rate: 1x //采样率
Wakeup Filter: Off //唤醒过滤器
PIC24HJ 和 dsPIC33FJ 设备 //同上
Baud Rate Prescalar: 4
Propagation Segment: 3xTq
Phase Segment 1: 2xTq
Phase Segment 2: 2xTq
Synchronized Jump Width: 1xTq
Sample Rate: 1x
Wakeup Filter: Off
///
///
(C) Copyright 1996,2010 Custom Computer Services
This source code may only be used by licensed users of the CCS C compiler. This source code may only be distributed to other
licensed users of the CCS C compiler. No other use, reproduction or distribution is permitted without written permission. Derivative programs created using this software in object code form are not restricted in any way.版权信息 翻译:羊兄台(billy)
///
#define CAN_DO_DEBUG TRUE
#if defined(__PCD__)
#include <24HJ256GP610.h>
#fuses PR,HS,NOWDT
#device adc=12
#use delay(clock=20MHz) //使用20M晶振
#use rs232(UART1, baud=9600) //使用UART1,波特率9600
#define CAN_BRG_PRESCALAR 4 //设置CAN波特率为125K
#define CAN_BRG_PHASE_SEGMENT_1 1 //Tq = (2(1+PRESCALAR))/(Fosc/2)
#define CAN_BRG_PHASE_SEGMENT_2 1 //Tq = (2(1+4)/(20000000/2) = 0.000001
#define CAN_BRG_PROPAGATION_TIME 2 //Baud Rate = 1/(((PHASE_SEGMENT_1+1)+(PHASE_SEGMENT_2+1)+(PROPAGATION_TIME+1)+(JUMP_WIDTH+1))*Tq)
#define CAN_BRG_SYNCH_JUMP_WIDTH 0 //Baud Rate = 1/(((1+1)+(1+1)+(2+1)+(0+1))*0.000001) = 125000
#include <can-PIC24.c>
#define PIN_LED1 PIN_B4
#define PIN_LED2 PIN_A5
#define PIN_LED3 PIN_B1
#else
#include <18F458.h>
#fuses HS,NOPROTECT,NOLVP,NOWDT //配置HS晶振,不用代码保护,不准低压编程,不用看门狗
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include <can-18xxx8.c> //CAN驱动库文件
#define PIN_LED1 PIN_A5
#define PIN_LED2 PIN_B5
#define PIN_LED3 PIN_B4
#endif
//定义LED灯状态
#define LED1_HIGH output_low(PIN_LED1)
#define LED1_LOW output_high(PIN_LED1)
#define LED2_HIGH output_low(PIN_LED2)
#define LED2_LOW output_high(PIN_LED2)
#define LED3_HIGH output_low(PIN_LED3)
#define LED3_LOW output_high(PIN_LED3)
//定义按键
#define BUTTON PIN_A4
#define BUTTON_PRESSED !input(BUTTON)
int16 ms;
//lcd显示字段
const char lcd_seg[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //0 for on, 1 for off
//定时器2 溢出中断
#int_timer2
void isr_timer2(void) {
ms++; //运行的定时器,产生需要的时钟
}
#define ASK_FOR_ID_AD_B 0x201 //向端口B的CAN要AD数据
#define SET_LED_ID_B 0x202 //给端口B的CAN设置LED值
#define RESPOND_TO_LED_C_ID 0x303
#define WRITE_REGISTER_C_ID 0x300
#define WRITE_REGISTER_D_ID 0x400
void main() {
int8 b_leds=0;
int8 c_leds=1;
int8 a_leds=0;
struct rx_stat rxstat;
unsigned int32 rx_id;
unsigned int8 buffer[8];
int8 rx_len;
unsigned int8 curr_lcd_output,last_lcd_output=0xFF;
#if defined(__PCD__)
unsigned int16 i;
#else
int8 i;
#endif
#if defined(__PCD__)
setup_adc(ADC_CLOCK_INTERNAL | ADC_TAD_MUL_31);
setup_adc_ports(sAN20 | VSS_VDD);
set_adc_channel(20);
#else
setup_port_a(RA0_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
#endif
for(i=0;i<8;i++) {
buffer[i]=0;
}
LED1_HIGH;
LED2_HIGH;
LED3_HIGH;
printf("\r\n\r\nCCS CAN EXAMPLE\r\n");
delay_ms(1000);
LED1_LOW;
LED2_LOW;
LED3_LOW;
#if defined(__PCD__)
setup_timer2(TMR_INTERNAL,10000); //设置定时器中断每1ms,如果使用20MHz的时钟
#else
setup_timer_2(T2_DIV_BY_4,79,16); //设置定时器中断每1ms,如果使用20MHz的时钟
#endif
can_init();
#if defined(__PCD__)
can_enable_b_transfer(TRB0); //缓冲器0发送缓冲器
#endif
enable_interrupts(INT_TIMER2);
#if defined(__PCD__)
enable_interrupts(INTR_GLOBAL);
#else
enable_interrupts(GLOBAL);
#endif
printf("\r\nRunning...");
while(TRUE)
{
if ( can_kbhit() )
{
printf("\r\n");
if(can_getd(rx_id, &buffer[0], rx_len, rxstat)) {
if (rx_id == ASK_FOR_ID_AD_B) {
printf("Channel B AD: %X\r\n",buffer[0]);
}
else if (rx_id == RESPOND_TO_LED_C_ID) { //节点C是一种mcp250x0的发出了一个信息,在边缘检测IO
printf("Chaning LEDs\r\n"); //in_data[0]=iointfl, in_data[1]=gpio
a_leds=~(buffer[1]);
if (bit_test(a_leds,4)) {LED1_HIGH;} else {LED1_LOW;}
if (bit_test(a_leds,5)) {LED2_HIGH;} else {LED2_LOW;}
if (bit_test(a_leds,6)) {LED3_HIGH;} else {LED3_LOW;}
}
}
}
if ( can_tbe() && (ms > 2000)) //当发送缓冲器为空,每两秒钟,发送新数据
{
ms=0;
//改变b端口LED状态
printf("\r\n\r\nSet LEDs on Port B to %U",b_leds);
can_putd(SET_LED_ID_B, &b_leds, 1, 1, 1, 0);
b_leds++;
if (b_leds > 7) {b_leds=0;}
}
if (BUTTON_PRESSED) {
while (BUTTON_PRESSED) {}
delay_ms(200);
//从端口b要AD数据
printf("\r\n\r\nAsking for A/D reading on Port B...");
can_putd(ASK_FOR_ID_AD_B, &buffer[0], 0, 1, 1, 0);
//改变c端口LED状态
buffer[0]=0x1E; //addr of gplat on 25050
buffer[1]=0x0E; //mask
buffer[2]=~(c_leds << 1); //new gplat values
printf("\r\nIncrementing LED on Port C");
can_putd(WRITE_REGISTER_C_ID, &buffer[0], 3, 1, 1, 0);
c_leds++;
if (c_leds > 7) {c_leds=0;}
}
//改变端口d的led字段
i=read_adc();
curr_lcd_output=i/410; //scale to 0-9
if (curr_lcd_output != last_lcd_output) {
last_lcd_output=curr_lcd_output;
printf("\r\nChanging 8-seg LCD on D to current A/D reading (%X, %X)",i,curr_lcd_output);
buffer[0]=0x1E; //addr of gplat
buffer[1]=0x7F; //mask
buffer[2]=lcd_seg[curr_lcd_output]; //new gplat values
can_putd(WRITE_REGISTER_D_ID, &buffer[0], 3, 1, 1, 0);
}
}
}