Насколько я понял, для ардуино можно писать программы на разных языках, в даже на бейсике и что более важно в данном конкретном случае на Си, поскольку существуют рабочие хорошо закомментированные исходники для AVR ....
Нашел интересную статью, о программировании на Си/Си++ для Ардуино
Может все таки не так сложно адаптировать?
Стыдно признаться, но я даже не знаю почему 4 файла? Догадываюсь что они должны скомпилироваться в файл который в дальнейшем и должен прошиваться в andurino...
Код файла main.h
PHP код:
//*************************************************************************
// Chrysler/Jeep CD changer emulator for J1850 bus
// by Michael Wolf
//
// Released under GNU GENERAL PUBLIC LICENSE
//
// contact: webmaster@mictronics.de
// homepage: www.mictronics.de
//
// Revision History
//
// when what who why
// 02/09/06 v1.00 Michael Initial release
//
//*************************************************************************
#ifndef __MAIN_H__
#define __MAIN_H__
// define bit macros
#define SETBIT(x,y) (x |= (y)) // Set bit y in byte x
#define CLEARBIT(x,y) (x &= (~y)) // Clear bit y in byte x
#define CHECKBIT(x,y) (x & (y)) // Check bit y in byte x
#endif // __MAIN_H__
Код файла main.c
PHP код:
//*************************************************************************
// Chrysler/Jeep CD changer emulator for J1850 bus
// by Michael Wolf
//
// Released under GNU GENERAL PUBLIC LICENSE
//
// contact: webmaster@mictronics.de
// homepage: www.mictronics.de
//
// Revision History
//
// when what who why
// 02/09/06 v1.00 Michael Initial release
//
//*************************************************************************
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "main.h"
#include "j1850.h"
int16_t main( void )
{
uint8_t j1850_rxmsg_buf[12]; // J1850 message buffer
uint8_t j1850_txmsg_buf[] = {0x8D, 0x93, 0x01, 0x00, 0x00, 0x00};
int8_t recv_nbytes; // byte counter
j1850_init(); // init J1850 bus
sei(); // enable global interrupts
for(;;)
{
recv_nbytes = j1850_recv_msg(j1850_rxmsg_buf); // get J1850 frame
if( !(recv_nbytes & 0x80) ) // proceed only with no errors
{
if( j1850_rxmsg_buf[0] == 0x8D ){
if( j1850_rxmsg_buf[1] == 0x0F ){
switch( j1850_rxmsg_buf[2] ){
default:
j1850_txmsg_buf[1] = 0x93;
j1850_txmsg_buf[2] = 0x01;
j1850_txmsg_buf[3] = 0x01;
j1850_txmsg_buf[4] = 0x80;
j1850_txmsg_buf[5] = j1850_crc( j1850_txmsg_buf,5);
j1850_send_msg(j1850_txmsg_buf, 6);
break;
case 0x21:
j1850_txmsg_buf[1] = 0x92;
j1850_txmsg_buf[2] = 0xC0;
j1850_txmsg_buf[3] = 0x00;
j1850_txmsg_buf[4] = 0x00;
j1850_txmsg_buf[5] = j1850_crc( j1850_txmsg_buf,5);
j1850_send_msg(j1850_txmsg_buf, 6);
j1850_txmsg_buf[1] = 0x92;
j1850_txmsg_buf[2] = 0xE1;
j1850_txmsg_buf[3] = 0x01;
j1850_txmsg_buf[4] = 0x03;
j1850_txmsg_buf[5] = j1850_crc( j1850_txmsg_buf,5);
j1850_send_msg(j1850_txmsg_buf, 6);
j1850_txmsg_buf[1] = 0x93;
j1850_txmsg_buf[2] = 0x01;
j1850_txmsg_buf[3] = 0x01;
j1850_txmsg_buf[4] = 0x80;
j1850_txmsg_buf[5] = j1850_crc( j1850_txmsg_buf,5);
j1850_send_msg(j1850_txmsg_buf, 6);
break;
case 0x24:
j1850_txmsg_buf[1] = 0x94;
j1850_txmsg_buf[2] = 0x00;
j1850_txmsg_buf[3] = 0x00;
j1850_txmsg_buf[4] = j1850_crc( j1850_txmsg_buf,4);
j1850_send_msg(j1850_txmsg_buf, 5);
break;
}
}
}
} // end if message recv
} // endless loop
return 0;
} // end of main()
Код файла j1850.h
PHP код:
//*************************************************************************
// Chrysler/Jeep CD changer emulator for J1850 bus
// by Michael Wolf
//
// Released under GNU GENERAL PUBLIC LICENSE
//
// contact: webmaster@mictronics.de
// homepage: www.mictronics.de
//
// Revision History
//
// when what who why
// 02/09/06 v1.00 Michael Initial release
//
//*************************************************************************
#ifndef __J1850_H__
#define __J1850_H__
/*** CONFIG START ***/
#define J1850_PORT_OUT PORTA // J1850 output port
#define J1850_DIR_OUT DDRA // J1850 direction register
#define J1850_PIN_OUT 2 // J1850 output pin
#define J1850_PORT_IN PINA // J1850 input port
#define J1850_PULLUP_IN PORTA // J1850 pull-up register
#define J1850_DIR_IN DDRA // J1850 direction register
#define J1850_PIN_IN 0 // J1850 input pin
#define J1850_PIN_OUT_NEG // define output level inverted by hardware
#define J1850_PIN_IN_NEG // define input level inverted by hardware
/*** CONFIG END ***/
#ifdef J1850_PIN_OUT_NEG
#define j1850_active() J1850_PORT_OUT &=~ _BV(J1850_PIN_OUT)
#define j1850_passive() J1850_PORT_OUT |= _BV(J1850_PIN_OUT)
#else
#define j1850_active() J1850_PORT_OUT |= _BV(J1850_PIN_OUT)
#define j1850_passive() J1850_PORT_OUT &=~ _BV(J1850_PIN_OUT)
#endif
#ifdef J1850_PIN_IN_NEG
#define is_j1850_active() bit_is_clear(J1850_PORT_IN, J1850_PIN_IN)
#else
#define is_j1850_active() bit_is_set(J1850_PORT_IN, J1850_PIN_IN)
#endif
/* Define Timer0 Prescaler here */
#define c_start_pulse_timer 0x02 // prescaler 8
#define c_stop_pulse_timer 0x00
// define error return codes
#define J1850_RETURN_CODE_UNKNOWN 0
#define J1850_RETURN_CODE_OK 1
#define J1850_RETURN_CODE_BUS_BUSY 2
#define J1850_RETURN_CODE_BUS_ERROR 3
#define J1850_RETURN_CODE_DATA_ERROR 4
#define J1850_RETURN_CODE_NO_DATA 5
#define J1850_RETURN_CODE_DATA 6
// convert microseconds to counter values
#define us2cnt(us) ((unsigned int)((unsigned long)(us) / (1000000L / (float)((unsigned long)MCU_XTAL / 8L))))
#define WAIT_100us us2cnt(100) // 100us, used to count 100ms
// define J1850 VPW timing requirements in accordance with SAE J1850 standard
// all pulse width times in us
// transmitting pulse width
#define TX_SHORT us2cnt(64) // Short pulse nominal time
#define TX_LONG us2cnt(128) // Long pulse nominal time
#define TX_SOF us2cnt(200) // Start Of Frame nominal time
#define TX_EOD us2cnt(200) // End Of Data nominal time
#define TX_EOF us2cnt(280) // End Of Frame nominal time
#define TX_BRK us2cnt(300) // Break nominal time
#define TX_IFS us2cnt(300) // Inter Frame Separation nominal time
// see SAE J1850 chapter 6.6.2.5 for preferred use of In Frame Respond/Normalization pulse
#define TX_IFR_SHORT_CRC us2cnt(64) // short In Frame Respond, IFR contain CRC
#define TX_IFR_LONG_NOCRC us2cnt(128) // long In Frame Respond, IFR contain no CRC
// receiving pulse width
#define RX_SHORT_MIN us2cnt(34) // minimum short pulse time
#define RX_SHORT_MAX us2cnt(96) // maximum short pulse time
#define RX_LONG_MIN us2cnt(96) // minimum long pulse time
#define RX_LONG_MAX us2cnt(163) // maximum long pulse time
#define RX_SOF_MIN us2cnt(163) // minimum start of frame time
#define RX_SOF_MAX us2cnt(239) // maximum start of frame time
#define RX_EOD_MIN us2cnt(163) // minimum end of data time
#define RX_EOD_MAX us2cnt(239) // maximum end of data time
#define RX_EOF_MIN us2cnt(239) // minimum end of frame time, ends at minimum IFS
#define RX_BRK_MIN us2cnt(239) // minimum break time
#define RX_IFS_MIN us2cnt(280) // minimum inter frame separation time, ends at next SOF
// see chapter 6.6.2.5 for preferred use of In Frame Respond/Normalization pulse
#define RX_IFR_SHORT_MIN us2cnt(34) // minimum short in frame respond pulse time
#define RX_IFR_SHORT_MAX us2cnt(96) // maximum short in frame respond pulse time
#define RX_IFR_LONG_MIN us2cnt(96) // minimum long in frame respond pulse time
#define RX_IFR_LONG_MAX us2cnt(163) // maximum long in frame respond pulse time
uint8_t timeout_multiplier; // default 4ms timeout multiplier
extern void j1850_init(void);
extern uint8_t j1850_recv_msg(uint8_t *msg_buf );
extern uint8_t j1850_send_msg(uint8_t *msg_buf, int8_t nbytes);
extern uint8_t j1850_crc(uint8_t *msg_buf, int8_t nbytes);
static inline void timer0_start(void)
{
TCCR0 = c_start_pulse_timer;
TCNT0 = 0;
}
static inline void timer0_stop(void)
{
TCCR0 = c_stop_pulse_timer;
}
#endif // __J1850_H__
Код файла j1850.c
PHP код:
//*************************************************************************
// Chrysler/Jeep CD changer emulator for J1850 bus
// by Michael Wolf
//
// Released under GNU GENERAL PUBLIC LICENSE
//
// contact: webmaster@mictronics.de
// homepage: www.mictronics.de
//
// Revision History
//
// when what who why
// 02/09/06 v1.00 Michael Initial release
//
//*************************************************************************
#include <avr/io.h>
#include "j1850.h"
/*
**---------------------------------------------------------------------------
**
** Abstract: Init J1850 bus driver
**
** Parameters: none
**
** Returns: none
**
**---------------------------------------------------------------------------
*/
void j1850_init(void)
{
j1850_passive(); // set VPW pin in passive state
J1850_DIR_OUT |= _BV(J1850_PIN_OUT); // make VPW output pin an output
J1850_PULLUP_IN |= _BV(J1850_PIN_IN); // enable pull-up on VPW pin
J1850_DIR_IN &=~ _BV(J1850_PIN_IN); // make VPW input pin an input
timeout_multiplier = 0x19; // set default timeout to 4ms * 25 = 100ms
}
/*
**---------------------------------------------------------------------------
**
** Abstract: Wait for J1850 bus idle
**
** Parameters: none
**
** Returns: none
**
**---------------------------------------------------------------------------
*/
static void j1850_wait_idle(void)
{
timer0_start();
while(TCNT0 < RX_IFS_MIN) // wait for minimum IFS symbol
{
if(is_j1850_active()) timer0_start(); // restart timer0 when bus not idle
}
}
/*
**---------------------------------------------------------------------------
**
** Abstract: Receive J1850 frame (max 12 bytes)
**
** Parameters: Pointer to frame buffer
**
** Returns: Number of received bytes OR in case of error, error code with
** bit 7 set as error indication
**
**---------------------------------------------------------------------------
*/
uint8_t j1850_recv_msg(uint8_t *msg_buf )
{
uint8_t nbits; // bit position counter within a byte
uint8_t nbytes; // number of received bytes
uint8_t bit_state;// used to compare bit state, active or passive
/*
wait for responds
*/
timer0_start();
while(!is_j1850_active()) // run as long bus is passive (IDLE)
{
if(TCNT0 >= WAIT_100us) // check for 100us
{
timer0_stop();
return J1850_RETURN_CODE_NO_DATA | 0x80; // error, no responds within 100us
}
}
// wait for SOF
timer0_start(); // restart timer1
while(is_j1850_active()) // run as long bus is active (SOF is an active symbol)
{
if(TCNT0 >= RX_SOF_MAX) return J1850_RETURN_CODE_BUS_ERROR | 0x80; // error on SOF timeout
}
timer0_stop();
if(TCNT0 < RX_SOF_MIN) return J1850_RETURN_CODE_BUS_ERROR | 0x80; // error, symbole was not SOF
bit_state = is_j1850_active(); // store actual bus state
timer0_start();
for(nbytes = 0; nbytes < 12; ++nbytes)
{
nbits = 8;
do
{
*msg_buf <<= 1;
while(is_j1850_active() == bit_state) // compare last with actual bus state, wait for change
{
if(TCNT0 >= RX_EOD_MIN ) // check for EOD symbol
{
timer0_stop();
return nbytes; // return number of received bytes
}
}
bit_state = is_j1850_active(); // store actual bus state
timer0_stop();
if( TCNT0 < RX_SHORT_MIN) return J1850_RETURN_CODE_BUS_ERROR | 0x80; // error, pulse was to short
// check for short active pulse = "1" bit
if( (TCNT0 < RX_SHORT_MAX) && !is_j1850_active() )
*msg_buf |= 1;
// check for long passive pulse = "1" bit
if( (TCNT0 > RX_LONG_MIN) && (TCNT0 < RX_LONG_MAX) && is_j1850_active() )
*msg_buf |= 1;
timer0_start(); // restart timer
} while(--nbits);// end 8 bit while loop
++msg_buf; // store next byte
} // end 12 byte for loop
// return after a maximum of 12 bytes
timer0_stop();
return nbytes;
}
/*
**---------------------------------------------------------------------------
**
** Abstract: Send J1850 frame (maximum 12 bytes)
**
** Parameters: Pointer to frame buffer, frame length
**
** Returns: 0 = error
** 1 = OK
**
**---------------------------------------------------------------------------
*/
uint8_t j1850_send_msg(uint8_t *msg_buf, int8_t nbytes)
{
if(nbytes > 12) return J1850_RETURN_CODE_DATA_ERROR; // error, message to long, see SAE J1850
j1850_wait_idle(); // wait for idle bus
timer0_start();
j1850_active(); // set bus active
while(TCNT0 < TX_SOF); // transmit SOF symbol
uint8_t temp_byte, // temporary byte store
nbits; // bit position counter within a byte
uint16_t delay; // bit delay time
do
{
temp_byte = *msg_buf; // store byte temporary
nbits = 8;
while (nbits--) // send 8 bits
{
if(nbits & 1) // start allways with passive symbol
{
j1850_passive(); // set bus passive
timer0_start();
delay = (temp_byte & 0x80) ? TX_LONG : TX_SHORT; // send correct pulse lenght
while (TCNT0 <= delay) // wait
{
if(!J1850_PORT_IN & _BV(J1850_PIN_IN)) // check for bus error
{
timer0_stop();
return J1850_RETURN_CODE_BUS_ERROR; // error, bus collision!
}
}
}
else // send active symbol
{
j1850_active(); // set bus active
timer0_start();
delay = (temp_byte & 0x80) ? TX_SHORT : TX_LONG; // send correct pulse lenght
while (TCNT0 <= delay); // wait
// no error check needed, ACTIVE dominates
}
temp_byte <<= 1; // next bit
}// end nbits while loop
++msg_buf; // next byte from buffer
} while(--nbytes);// end nbytes do loop
j1850_passive(); // send EOF symbol
timer0_start();
while (TCNT0 <= TX_EOF); // wait for EOF complete
timer0_stop();
return J1850_RETURN_CODE_OK; // no error
}
/*
**---------------------------------------------------------------------------
**
** Abstract: Calculate J1850 CRC
**
** Parameters: Pointer to frame buffer, frame length
**
** Returns: CRC of frame
**
**---------------------------------------------------------------------------
*/
uint8_t j1850_crc(uint8_t *msg_buf, int8_t nbytes)
{
uint8_t crc_reg=0xff,poly,byte_count,bit_count;
uint8_t *byte_point;
uint8_t bit_point;
for (byte_count=0, byte_point=msg_buf; byte_count<nbytes; ++byte_count, ++byte_point)
{
for (bit_count=0, bit_point=0x80 ; bit_count<8; ++bit_count, bit_point>>=1)
{
if (bit_point & *byte_point) // case for new bit = 1
{
if (crc_reg & 0x80)
poly=1; // define the polynomial
else
poly=0x1c;
crc_reg= ( (crc_reg << 1) | 1) ^ poly;
}
else // case for new bit = 0
{
poly=0;
if (crc_reg & 0x80)
poly=0x1d;
crc_reg= (crc_reg << 1) ^ poly;
}
}
}
return ~crc_reg; // Return CRC
}