準備用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);
}
}
}