// *********************************************************** // Project: Loadcell to RS232 Interface via HX711, // Micrometer via Heidenhain TTL to RS232 // Author: Dr. Simon Schroedle // Started: 12/2017 // Module description: Standalone to run on ATMEGA329P // data are transmitted as HEX values // D: linear encoder data // S: Error count linear encoder (invalid code transitions) // W: load cell data // T: time stamp // *********************************************************** // configuration #define F_CPU 16000000UL #define HX711_CLOCK_PIN C,0 #define HX711_DATA_PIN C,1 #define LENC_A0_PIN C,2 //note: bits hardcoded in ISR #define LENC_A1_PIN C,3 #define TESTPIN B,0 //for timing measurements #include #include #include #define BAUD 19200UL #define UBRR_BAUD ((F_CPU/(16UL*BAUD))-1) #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) /// Set the specified pin high. #define AVRPIN_SET(x) __AVRPIN_SET(x) #define __AVRPIN_SET(p,b) PORT##p |= 1<>8); UBRR0L = (uint8_t) (UBRR_BAUD & 0x0ff); UCSR0B = (1<>4)&0x0fL]); usend (ihex[(value)&0x0fL]); } static uint8_t hx711_last_timeh; //timer1 high register static uint8_t hx711_last_timel; // ... low register int hx711_read_32( int32_t* pvalue ) { int32_t value = 0; uint8_t i; if( AVRPIN_PIN( HX711_DATA_PIN ) ) { return 0; } hx711_last_timel = TCNT1L; //store timestamp hx711_last_timeh = TCNT1H; // clock out the bits for( i=0; i<24; i++ ) { AVRPIN_SET( HX711_CLOCK_PIN ); asm("nop"); asm("nop"); AVRPIN_CLR( HX711_CLOCK_PIN ); value <<= 1; if( AVRPIN_PIN( HX711_DATA_PIN ) ) { value |= 1; } asm("nop"); asm("nop"); } // select the channel and the gain for the next conversion AVRPIN_SET( HX711_CLOCK_PIN ); asm("nop"); asm("nop"); AVRPIN_CLR( HX711_CLOCK_PIN ); asm("nop"); asm("nop"); *pvalue = value; return 1; } signed char graytab[]={0,1,-1,0x10, -1,0,0x10,1, 1,0x10,0,-1, 0x10,-1,1,0}; /*0x10: error, more than one bit changed */ volatile uint8_t qinp; volatile uint8_t merror; volatile int16_t lenc_pos; ISR (TIMER0_COMPA_vect) // timer0 overflow interrupt { signed char delta; // AVRPIN_SET(TESTPIN); qinp>>=2; /* new state in bit 3,2; old state in bit 1,0 */ qinp|=(AVRPORT_PIN2(LENC_A0_PIN)&0x0c); /* new state in bit 3,2 */ delta=graytab[qinp]; if (delta==0x10) { delta=0; merror++; } lenc_pos+=delta; // AVRPIN_CLR(TESTPIN); } int main(void) { int32_t value; int16_t enc_value; uart_init(); usend ('%'); //to say hello to the host usend ('%'); AVRPIN_MKIN( LENC_A0_PIN); AVRPIN_MKIN( LENC_A1_PIN); // hx711_init AVRPIN_SET_VALUE( HX711_CLOCK_PIN, 0 ); AVRPIN_MKOUT( HX711_CLOCK_PIN ); AVRPIN_MKIN( HX711_DATA_PIN ); AVRPIN_MKOUT(TESTPIN); // CTC mode timer TCCR0A |= (1 << WGM01); // timer limit for INT OCR0A = 128; //125 khz TIMSK0 |= (1 << OCIE0A); //COMPA vect TCCR0B |= (1 << CS00); // no prescale TCCR1B |= (1 << CS12) | (1 << CS10); // set prescaler to 1024 and start the timer //this is for the timestamp, 0.064 ms resolution sei(); // enable interrupts while (1) { if ( hx711_read_32( &value ) ) //transmission are triggered by //hx711 conversions, about 12 Hz { enc_value=lenc_pos; // AVRPIN_SET(TESTPIN); usend ('D'); usend (ihex[(enc_value>>12)&0x0fL]); usend (ihex[(enc_value>>8)&0x0fL]); usend (ihex[(enc_value>>4)&0x0fL]); usend (ihex[enc_value&0x0fL]); usend ('S'); usend (ihex[merror>>4&0x0fL]); //error count usend (ihex[merror&0x0fL]); //error count usend ('W'); usend (ihex[(value>>20)&0x0fL]); usend (ihex[(value>>16)&0x0fL]); usend (ihex[(value>>12)&0x0fL]); usend (ihex[(value>>8)&0x0fL]); usend (ihex[(value>>4)&0x0fL]); usend (ihex[value&0x0fL]); usend ('T'); usend (ihex[(hx711_last_timeh>>4)&0x0f]); usend (ihex[hx711_last_timeh&0x0f]); usend (ihex[(hx711_last_timel>>4)&0x0f]); usend (ihex[hx711_last_timel&0x0f]); // AVRPIN_CLR(TESTPIN); } } return 0; }