# Baby-o and 7 segments

I want to communicate with my baby-o and so far I used a LCD for entering parameters or displaying values. The demo3 software of the LV168 was very helpful.

Now I want to save weight by using a 4 character 7 digit display. My intention is to hook up the abcdefg lines with a 220 Ohm resistor to the PB and PD outputs and the common anode to the M1 and M2 outputs. The power is applied by a 4,8Volt battery. 4,8V/220 Ohm = approx 40 mA, is that allowed?

I want to display both text and numbers, with the LCD I use lcd.c and lcd.h which makes life very easy, just copy the pinout from the LV168 and it will work after initiating the lcd very easily.

Is there a program available to include in my program that does the multiplexing and translation of values and text to the right pins?

Your calculation is wrong: (4.8 V)/(220 Ohms) is actually 21.8 mA, but your I/O pins will actually be using less current than that because you did not account for the voltage drop across the diode.

According to the Sec 28.1 of the ATmega328p datasheet you can have at most 40 mA per I/O pin (you’re under that) and 200 mA on the GND and VCC pins (your 7-segment display needs less than 7*20 = 140 mA). So the Baby Orangutan should work.

Are you aware of the Pololu AVR Library we provide? It has some functions that will help you get started, like the motor control functions and digital I/O functions.

We don’t provide any software specifically for 7-segment displays but if you search around for “avr 7-segment display” you might find something useful. Here are some Arduino people who got it working and shared their code:
arduino.cc/cgi-bin/yabb2/YaB … 1270945405
Since the Arduino is based on the same chip as the Baby Orangutan you should be able to get their code working on the Baby Orangutan.

Controlling this display is going to be harder than controlling an LCD because you are only going to be able to light up one digit at a time, so you will need to write code that quickly (every couple milliseconds or so) changes to the next digit. It’s not like the LV-168 LCD where you can just send the LCD a command and then use your entire CPU to do something else.

I noticed that Sparkfun sells a compact 4-digit 7-segment display. You should consider using this because you would be able to control over serial using just one pin (PD1) of the Baby Orangutan and the programming you need to do would be easier (the Pololu AVR Library makes it easy to send serial commands). They also provide their source code, so that might help you. And their unit is based on an ATmega168 so you can easily reprogram it if you want, using the same tools you use to program the Baby Orangutan. (Unfortunately it is out of stock right now.)

–David

Thanks for the info, I am aware of the library and use it a lot.

I got some 7 segments from a friend to play with. Some very old Texas Instruments which happen to be common cathode. These cannot be switched on and off with the motor outputs.

I found some 3 digit 7 segments common anode on ebay. As I look for minimum weight I do not want to go for serial communication. There are enough pins PB-PD on the baby-o for my application. An XYZ gravity sensor is hooked up to PC1-2-3.

This is what I want the application to do:
When the battery is connected it should wait to run its program until PD7 is grounded. (that is easy)
If PD7 is pressed for 2 seconds it should go to the parameter menu, the display should show the parameter name like PPF (proportional factor) and increase/ decrease when the robot is tilted forward or backwards. Pressing PD7 should write this to the eeprom memory.
Resetting is done by disconnecting the battery.

I have this program working with the LCD and the three push buttons and copied the hardware layout from the 168LV.

I will update this post with the progress made

It took me some time but here it is, a baby O that remembers a setting.

When you put the program on the baby-O the value sec will not be set, it blinks SEC and 8, when the button PD7 is kept for more than 1 second it goes to the adjust mode, turn the potmeter on ADC7 left or right to increase or decrease the number. If it does not change anymore for three seconds it writes the value to the eeprom memory and starts counting down.

The next time the power is put on the device it blinks SEC and the VALUE youjust saved. A short push on the button starts the counting down sequence.

I needed a lot of code:

``````#include <avr/io.h>
#include "device.h"	// pinout definitions for the baby-O adapted for use with the 7 segment display
#include <util/delay.h> // F_CPU is defined in "device.h" above
#include <avr/eeprom.h>	// provides eeprom routines
#include <avr/interrupt.h> // provides interrupt routines for the time counting

volatile uint16_t tim;
volatile uint16_t tel;
uint16_t sec; // parameter sec
uint16_t para; // secondary values

ISR(TIMER2_COMPA_vect)
{
tel = (tel + 1);
if (tel >= 1220)
{ (tim = (tim + 1)); tel = 0; }
}

void delay_ms( unsigned int time_ms ) // delay for time_ms milliseconds by looping
{
unsigned int i;

for ( i = 0; i < time_ms; i++ )
_delay_ms( 1 ); // _delay_ms() comes from <util/delay.h>
}

void SegmentOn(uint16_t n) // truth table for segments
{
if ( n == 0 ) { PORTD |= 1 << G; }
if ( n == 1 ) { PORTB |= 1 << A; PORTD |= 1 << D; PORTD |= 1 << E; PORTB |= 1 << F; PORTD |= 1 << G; }
if ( n == 2 ) { PORTD |= 1 << C; PORTB |= 1 << F; }
if ( n == 3 ) { PORTD |= 1 << E; PORTB |= 1 << F; }
if ( n == 4 ) { PORTB |= 1 << A; PORTD |= 1 << E; PORTD |= 1 << D; }
if ( n == 5 ) { PORTB |= 1 << B; PORTD |= 1 << E; }
if ( n == 6 ) { PORTB |= 1 << B; }
if ( n == 7 ) { PORTD |= 1 << D; PORTD |= 1 << E; PORTB |= 1 << F; PORTD |= 1 << G; }
if ( n == 8 ) { }
if ( n == 9 ) { PORTD |= 1 << E; }
}

void DigitOn(digit)	// truth table for switching on M1A, M1B, M2A, M2B
{
if ( digit == 3 ) { PORTD |=  ( 1 << D1 ); PORTD &= ~( 1 << D2 ); PORTB &= ~( 1 << D3 ); PORTD &= ~( 1 << D4 ); }
if ( digit == 1 ) { PORTD &= ~( 1 << D1 ); PORTD |=  ( 1 << D2 ); PORTB &= ~( 1 << D3 ); PORTD &= ~( 1 << D4 ); }
if ( digit == 4 ) { PORTD &= ~( 1 << D1 ); PORTD &= ~( 1 << D2 ); PORTB |=  ( 1 << D3 ); PORTD &= ~( 1 << D4 ); }
if ( digit == 2 ) { PORTD &= ~( 1 << D1 ); PORTD &= ~( 1 << D2 ); PORTB &= ~( 1 << D3 ); PORTD |=  ( 1 << D4 ); }
}

void Off()
{
PORTB &= ~( 1 << A ); PORTB &= ~( 1 << B ); PORTB &= ~( 1 << F );
PORTD &= ~( 1 << D ); PORTD &= ~( 1 << E ); PORTD &= ~( 1 << C ); PORTD &= ~( 1 << G );
PORTD &= ~( 1 << D1 ); PORTD &= ~( 1 << D2 ); PORTB &= ~( 1 << D3 ); PORTD &= ~( 1 << D4 );
}

void Seg_Off()
{
PORTB &= ~( 1 << A ); PORTB &= ~( 1 << B ); PORTB &= ~( 1 << F );
PORTD &= ~( 1 << D ); PORTD &= ~( 1 << E ); PORTD &= ~( 1 << C ); PORTD &= ~( 1 << G );
}

void Show_SEC() // Shows time name
{
unsigned int i;

for (i = 0; i < 250; i++)
{
PORTB |= 1 << B; PORTD |= 1 << C; PORTD |= 1 << G;	// Send C segments to LED
DigitOn(3);											// Turn on fourth digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
PORTB |= 1 << B; PORTD |= 1 << C;					// Send E segments to LED
DigitOn(2);											// Turn on third digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
PORTB |= 1 << B; PORTD |= 1 << E;					// Send S segments to LED

DigitOn(1);											// Turn on second digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
// Send no segments to LED
//DigitOn(4);										// Turn on first digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting

if ( (PIND & (1 << PD7)) == 0 )						// if pin PD7 is grounded
{ break; }											// onderbreek loop
}
}

{
uint16_t number; number = 0;
uint16_t laag; laag = 0;
uint16_t hoog; hoog = 0;

unsigned int avg;

unsigned int i;

for (i = 0; i < 750; i++)
{
number = (para)%10;									// Convert number to segments
if ( para < 1 ) { number = 0; }						// force zero as output
SegmentOn(number);									// Send segments to LED
DigitOn(4);											// Turn on fourth digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
number = (para/10)%10;								// Convert number to segments
SegmentOn(number);									// Send segments to LED
if ( para >   9 ) { DigitOn(3); }					// Turn on third digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
number = (para/100)%10;								// Convert number to segments
SegmentOn(number);									// Send segments to LED
if ( para >  99 ) { DigitOn(2); }					// Turn on second digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
number = (para/1000)%10;							// Convert number to segments
SegmentOn(number);									// Send segments to LED
if ( para > 999 ) { DigitOn(1); }					// Turn on first digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting

while ( ADCSRA & ( 1 << ADSC ))	;					// wait while converting

if ( para >= 1 )
{
if ( avg <= 300 )   { laag = ( laag + (( 300 - avg )/2)); };
if ( laag >= 5000 ) { para = ( para - 1 ); laag = 0; i = 0; };
}
if ( para <= 2500 )
{
if ( avg >= 370 )   { hoog = ( hoog + (( avg - 370 )/2)); };
if ( hoog >= 5000 ) { para = ( para + 1 ); hoog = 0; i = 0; };
}

if ( para >= 2500 ) { para = 2500; }				// limit ESC value to 100% Furtaba
if ( para >= 3000 ) { para = 0; }					// limit any parameter >= 0

if ( (PIND & (1 << PD7)) == 0 )						// if pin PD7 is grounded
{ break; }											// onderbreek loop
}
return para;
}

void Show(para) // Shows parameter value
{
uint16_t number; number = 0;

unsigned int i;

for (i = 0; i < 234; i++)								// counts 18 seconds in 18 seconds
{
number = (para)%10;									// Convert number to segments
SegmentOn(number);									// Send segments to LED
DigitOn(4);											// Turn on fourth digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
number = (para/10)%10;								// Convert number to segments
SegmentOn(number);									// Send segments to LED
if ( para >   9 ) { DigitOn(3); }					// Turn on third digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
number = (para/100)%10;								// Convert number to segments
SegmentOn(number);									// Send segments to LED
if ( para >  99 ) { DigitOn(2); }					// Turn on second digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting
number = (para/1000)%10;							// Convert number to segments
SegmentOn(number);									// Send segments to LED
if ( para > 999 ) { DigitOn(1); }					// Turn on first digit
delay_ms(1);										// Leave it on 1 ms
Off();												// Turn off digit to prevent ghosting

if ( (PIND & (1 << PD7)) == 0 )						// if pin PD7 is grounded
{ break; }											// onderbreek loop
}
}

int main( void )
{
DDRB |= (1 << A) | (1 << B) | (1 << F);				// set LED pin to output
DDRD |= (1 << D) | (1 << E) | (1 << C) | (1 << G);	// set LED pin to output

DDRD  &= ~(1 << PD7);		// make pin PD7 an input, this is the start/ reset button
PORTD |=  (1 << PD7);		// enable pull-up on pin PD7 (this means pin PD7
// will read as high unless externally driven low)

// Set timer 2 voor tijdmeting via ISR routine
TCCR2B |= (1 << WGM22); 	// Configure timer 2 for CTC mode
TIMSK2 |= (1 << OCIE2A); 	// Enable CTC interrupt
sei(); 						// Enable global interrupts
OCR2A   = 250; 				// Set CTC compare value with a prescaler of 64
TCCR2B |= ((1 << CS22)); 	// Start timer at Fcpu/64

while ( (PIND & (1 << PD7)) == 0 ) { delay_ms(1);}	// waits here after reset until switch is released

//*********************************Wacht op start*****************************************

while (1)
{
Show_SEC();								// Show parameter name

Show(sec);								// Shows value of the parameter

if ( (PIND & (1 << PD7)) == 0 ) 		// goto next if pin PD7 is grounded
{ break; }

}

delay_ms(1000);							// Wait whether we keep the switch grounded longer than one second

if ( (PIND & (1 << PD7)) == 0 ) 		// goto next if pin PD7 is kept grounded for more than 1 second
{

while ( (PIND & (1 << PD7)) == 0 ) { delay_ms(1);}	// waits here until switch is released

Show_SEC();								// Show parameter name

if ( sec >= 5000 ) { sec = 320;} 		// write initial value before using parameter
sec = adjust(sec);						// give adjust para a time out for loop (3 seconds)
eeprom_write_word((uint16_t*)12,sec);	// writes to eeprom memory

}

//**********************************Walk to Handle time************************************
// reset by nose dowm

unsigned int z;
for (z = 0; z <= sec; z = ( z + 1))				// Tel af van 18
{
Show(sec - z);

}

return 0;
}
``````

The 7 segment was connected to port B 1,4,5 and D 0,1,2,4 with 220 ohm resistors The digits were connected to the M1A/B and M2 A/B outputs. The current was limited to 14 mA per segment.

device.h was modified to this defiition:

``````// Taken from Tom Benedict's Orangutan-lib
// Modified by Ben Schmidel to work with the Orangutan LV-168
// Modified by Erik Janssen to work with the Baby-O 168

#ifndef _DEVICE_
#define _DEVICE_

/////////////////////////////////////////////////////////////////////
// Baby-O-168 pin assignments                                //
/////////////////////////////////////////////////////////////////////

#ifndef F_CPU
#define F_CPU 20000000UL
#endif 								//!F_CPU

// Onboard buzzer:

#define BUZZER_DDR			DDRB
#define BUZZER_PORT			PORTB
#define BUZZER_BIT			PB2

// Onboard LEDs:

// 7 Segment

// On the Baby-O LV-168, the 7 segments control lines are split between
// ports B and D:

#define SEG_A_B_C_D_DDR		DDRD
#define SEG_A_B_C_D_PORT	PORTD
#define SEG_E_F_G_DDR		DDRB
#define SEG_E_F_G_PORT		PORTB
#define A				PB0
#define F				PB4
#define B				PB5
#define E				PD0
#define D				PD1
#define C				PD2
#define G				PD4

// ***** Character digit PINS *****
#define D2					PD5		// used to control digit 2
#define D1					PD6		// used to control digit 1
#define D4					PD3		// used to control digit 3
#define D3					PB3		// not used for the 3 character example, may be used for 4 character *** NOTE: M2A is on port B, not port D

#endif //_DEVICE_
``````