MetkuMods

Kuinka pääset alkuun mikrokontrollereiden kanssa - Osa 2.

Kommunikointi tietokoneen kanssa, moottorien ohjaus, servot jne.
 
Kirjoittaja: Aki Korhonen
Julkaistu: 06.05.2009
In English In English
Suomeksi Suomeksi

Esimerkki 2.5 - Tietokoneeseen yhdistäminen

Opittava asia: tiedonsiirto mikrokontrollerin ja tietokoneen välillä.

Osalista:
  • ATmega8 tai ATmega88 (tai mikä tahansa sisäänrakennetulla UART:lla, esim. ATtiny2313)
  • 100 nF kondensaattori
  • 1 µF elektrolyyttikondensaattori
  • MAX233 (samanlainen MAX232:n kanssa, muttei tarvitse ulkoisia kondensaattoreita)
  • Punainen ledi
  • 270 ohmin vastus, ledin etuvastus (käytä LedCalcia etuvastuksien laskemiseen muunlaisille ledeille)
 

How to get started with microcontrollers - Part 2
Esimerki 2.5

 

How to get started with microcontrollers - Part 2
Esimerkki 2.5

Saatuasi laitteen kasaan ja tarkistettuasi kytkennät, yhdistä laite tietokoneesi sarjaporttiin tai USB-sarjaliitäntäadapteriin. Aukaise jokin terminaaliohjelma, valitse oikea COM-portti ja laita asetuksiksi seuraavat: baud rate 2400, 8 data bits, 1 stop bit, no parity.

Paina yhdistämisnappia ja laita virrat päälle laitteeseen ja mikäli kaikki on kunnossa, tulisi laitteen ledin vilkkua pari kertaa ja terminaaliohjelmasi ruudulla lukea "Hello". Jos ei, niin tarkista kaikki asetukset ja kytkennät.

Mikäli lähetät ohjelmalla A-kirjaimen (iso 'A', ei 'a'), niin ledin tulisi syttyä ja tekstin "ON" tulla ruutuun. Lähettämällä B-kirjaimen, ledi sammuu ja ruudulle tulee teksti "OFF".


/**
* MetkuMods - http://metku.net/
* Kuinka pääset alkuun mikrokontrollereiden kanssa - Osa 2
* Esimerkki 2.5 - Tietokoneeseen yhdistäminen
*
* Tekijä: Aki Korhonen
* Pvm: 2009-04-29
*/

// Mikäli kellotaajutta ei ole projektiasetuksissa laitettuna, niin laitetaan tässä
#ifndef F_CPU
	#define F_CPU 1000000UL // 1 MHz
#endif

// Haluttu baudinopeus, 2400 bps toimii hyvin 1 MHz sisäisellä kellolla
#define BAUD 2400

#include <avr/io.h>

#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <util/setbaud.h>

// Ledi pinnissä PB0
#define LED1_PIN 0

// Funktioiden prototyyppejä
void Init_USART(void);
void USART_SendByte(uint8_t data);
uint8_t USART_ReceiveByte(void);

// Pääohjelma
int main(void)
{
	// PB0 ulos
	DDRB = _BV(LED1_PIN);

	// Aseta kaikki pinnit portissa B alas
	PORTB = 0x00;

	// Aseta UART toimintaan
	Init_USART();
	
	// Vilkutellaan lediä pari kertaa, että kaikki ok
	PORTB |= _BV(LED1_PIN); // Sytytä ledi
	_delay_ms(100); // Odota 100 ms
	PORTB &= ~(_BV(LED1_PIN)); // Sammuta ledi
	_delay_ms(100);
	PORTB |= _BV(LED1_PIN);
	_delay_ms(100);
	PORTB &= ~(_BV(LED1_PIN));
	_delay_ms(100);

	// Lähetä lyhyt viesti tietokoneelle lähetyksen testausta varten
	// Terminaaliohjelman ruudulle tulisi ilmestyä teksti "Hello"
	USART_SendByte('H');
	USART_SendByte('e');
	USART_SendByte('l');
	USART_SendByte('l');
	USART_SendByte('o');
	USART_SendByte('\n');

	// Aktivoi globaalit keskeytykset
	sei();
	
	while(1)
	{
		// Mitään ei tehdä täällä, kaikki työ tehdään keskeytyksissä.
		// Tämä looppi tarvitaan silti pitämään kontrolleri toiminnassa.
	}

	return 0;
}

// Vastaanottokeskeytys, tämä suoritetaan, kun dataa tulee RX-linjaa pitkin
ISR(USART_RXC_vect)
{
	uint8_t c;
	
	// Hae tulossa oleva tavu
	c = USART_ReceiveByte();
	
	if(c == 'A')
	{
		// Mikäli vastaanotettu tavu vastaa ASCII-merkkiä A, sytytä ledi
		PORTB |= _BV(LED1_PIN);

		USART_SendByte('O');
		USART_SendByte('N');
		USART_SendByte('\n');
	}
	else if(c == 'B')
	{
		// Mikäli vastaanotettu tavu vastaa ASCII-merkkiä B, sammuta ledi
		PORTB &= ~(_BV(LED1_PIN));

		USART_SendByte('O');
		USART_SendByte('F');
		USART_SendByte('F');
		USART_SendByte('\n');
	}
}

// UART:n asetus
void Init_USART(void)
{
	UBRRH = UBRRH_VALUE;
	UBRRL = UBRRL_VALUE;
	
	UCSRA = 0x00;
	UCSRB |= (1 << RXEN); // RXEN, aktivoi vastaanotto
	UCSRB |= (1 << RXCIE); // RXCIE, aktivoi vastaanottokeskeytys
	UCSRB |= (1 << TXEN); // TXEN, aktivoi lähetys
	UCSRC = 0x86; // 8 Data bits, 1 Stop bits, No Parity
}

// SendByte lähettää halutun tavun TX-linjalle
void USART_SendByte(uint8_t data)
{
	// Odotellaan mikäli tavun lähetys on kesken
	loop_until_bit_is_set(UCSRA, UDRE);

	// Lähetä parametrina saatu data
	UDR = data;
}

// ReceiveByte lukee tavun RX-linjalta
uint8_t USART_ReceiveByte(void)
{
	// Odotellaan, että tavu on kokonaan vastaanotettu
	loop_until_bit_is_set(UCSRA, RXC);

	// Palauta vastaanotettu data
	return UDR;
}


Yhteenveto

Toivottavasti tämä artikkeli antoi sinulle lisää ideoita mikrokontrollereiden käyttöön. Nämä esimerkit ovat vasta jäävuoren huippu siitä mitä kaikkea mikrokontrollereilla voi tehdä, joten yhdistelemällä erilaisia ominaisuuksia, saat käytettyä niitä rajattomassa määrässä erilaisia sovelluksia. Artikkelin perään voit lähettää kysymyksesi ja kommenttisi, sekä halutessasi ehdottaa ideoita seuraavan osan sisältöön liittyen.

Jälleen kerran, muistathan rekisteröityä ja lähettää kuvia rakennelmistasi AllTheModsiin (muutkin modikuvasi ovat toki tervetulleita!)

Nähdään kolmannessa osassa!

Subscribe to Metku.net
Digg It
Save This Page
Stumble it!
Add to Facebook


Aiheeseen liittyviä artikkeleja Metkussa:


Kuinka pääset alkuun mikrokontrollereiden kanssa - Osa 1.


Monikerroskaiverruksen animointi


Vilkkuvalot part 2


Modaajan lyhyt sähköoppi


ColorFade


HDD Eyez


Osallistu keskusteluun. Artikkeliin liittyvä viestiketju foorumissa.
  • 06.05.2009 12:35 zaketus

  • Great examples with schematics, photos of circuit on breadboard and well commented source codes... Isn't that all we could wish for?

    Hyviä esimerkkejä kytkentäkaavioilla, kuvilla koekytkentäalustalle kasatuista piireistä ja hyvin kommentoiduilla lähdekoodeilla... Eikös siinä ole melkein kaikki mitä voidaan toivoa?
  • 09.05.2009 00:36 Opelrun

  • Loistava opastus mikrokontrollien maailmaan :D
  • 13.05.2009 17:50 Zyrppa

  • Vihdoin selvästi tehty ja helposti ymmärrettävä ohje ledin ohjaamiseen pwm:llä!
    ATtiny2313:ssa ei taida olla tuota PWM:ää sisäänrakennettuna? Täytyykin kokeilla, jos saisin tuosta esimerkki koodista väsäiltyä RGB-ledeille ohjaimen jossa väriä säädetään napeilla.
  • 13.05.2009 22:17 zaketus

  • ATtiny2313:ssa on nelikanavainen PWM...

    Lähde: www.avrfreaks.com

    Freakseissa kun klikkaa etusivulla "DEVICES" tabia ja sitten kirjoittaa hakuun piirin mallin, saa paljon tärkeää tietoa piiristä. Tosi kätevä vertailla eri piirejä ja päättää, minkä lähikaupan valikoimissa olevan piirin ostaisi.
  • 06.08.2009 20:37 slander

  • En ole nyt täysin varma mutta näyttäisi siltä, että esimerkin 2.5 kuvissa on pientä ristiriitaisuutta. Kytkentäkaaviossa on MAX233 piirin pinni 7 vedetty +5V:iin mutta koekytkentälevyllä +5V on kytkettykin pinniin 8.
  • 06.08.2009 20:52 zaketus

  • Ainakin seiskan pitäisi olla tosiaan +5v, kuten kytkentäkaaviossa onkin. Kaheksaista ei tarvitse kytkeä mihinkään.
  • 29.08.2009 20:46 toffie

  • Hey all, I've just this past week finally got some components to try out some projects I've been wanting to do for some time now..

    But I'm not able to compile the code straight on cause of some errors that you can see below.
    Can you help me out with what may be wrong?

    Thanks in advance =)

    edit.. I know you can see it in the log text, but I'm using a mega32 instead of the one you used..
    but I guess it should work anyway, without altering the code cause this is some code error right?


    Build started 29.8.2009 at 19:36:41
    avr-gcc -mmcu=atmega32 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT metku.o -MF dep/metku.o.d -c ../metku.c
    ../metku.c: In function 'main':
    ../metku.c:42: error: 'TCCR0A' undeclared (first use in this function)
    ../metku.c:42: error: (Each undeclared identifier is reported only once
    ../metku.c:42: error: for each function it appears in.)
    ../metku.c:46: error: 'COM0A1' undeclared (first use in this function)
    ../metku.c:50: error: 'TCCR0B' undeclared (first use in this function)
    ../metku.c:86: error: 'OCR0A' undeclared (first use in this function)
    make: *** [metku.o] Error 1
    Build failed with 6 errors and 0 warnings...
  • 29.08.2009 20:56 toffie

  • I just noticed that it was because I used another uC.. so I'll have to find out the new names of the variables to see if that works..

    cause when I changed to ATtiny45 and tried to compile it worked just fine :D
    so it clearly is a uC problem in the code, so I'll try and port it.. if I get it to work I can post it here if there are any interest :)
  • 29.08.2009 21:11 japala

  • Please do share. I'm sure there are people that would like to start directly with more powerful chips.
  • 29.08.2009 21:29 toffie

  • well here we go then.. here are the updated code for use with mega32..
    however, I'm not able to get any voltage over the led..

    I've both tried with port B and A and there are no differences.. I dont get any voltage either before
    or after the resistor for the led.. the pot works and gives
    correct readings and that far it goes well but then
    coming out of the uC seems to be the problem..

    any ideas on how to solve it?
    I'm 100% sure about the connections as I've gone through the schematic a few times and
    checked on different leads to see if it's correct and so..




    /**
    * MetkuMods - http://metku.net/
    * How to get started with AVR microcontrollers, part 2
    * Example 2.3.2 - Reading the value of a potentiometer
    *
    * Author: Aki Korhonen
    * Date: 2009-04-29
    */

    // If clock speed isn't set in the project settings then it is set here
    #ifndef F_CPU
    #define F_CPU 1000000UL // 1 MHz
    #endif

    #include
    #include

    #include

    // Led at PB0, (OCR0A)
    #define LED 0

    // Potentiometer slide at PB2, (ADC1)
    #define POT 2

    int main(void)
    {
    // PB2 in, others out
    DDRB = 0b11011;
    PORTB = 0x00;

    // Value for the register
    // "value" equals brightness of the led
    // 0 = off | 255 = full brightness
    uint8_t value = 0;

    // -------------------------
    // Initialize PWM

    // 8-bit PWM, Phase correct
    // 8 bits give us 256 levels of brightness
    TCCR1A |= (1<
    // Clear OC0A/OC0B on Compare Match
    // Set OC0A/OC0B at BOTTOM (non-inverting mode)
    TCCR1A |= (1<
    // Set prescaler to 8
    // 1 MHz / 8*256 = ~490 Hz PWM frequency
    TCCR1B |= (1<
    // -------------------------
    // Initialize ADC

    // Enable ADC
    ADCSRA = (1<
    // Select ADC1
    ADMUX |= (1<
    // Use Vcc as voltage reference
    ADMUX &= ~(1<
    // Select divider factor 8, so we get 1 MHz/8 = 125 kHz ADC clock
    ADCSRA |= (1<
    // -------------------------

    // The program reads the ADC value from the potentiometer slide
    // all the time and updates the PWM register with that value so
    // the led brightness is controlled with the potentiometer.
    while(1)
    {
    // Start ADC conversion
    ADCSRA |= (1<
    // Wait until the conversion is ready
    loop_until_bit_is_set(ADCSRA, ADSC);

    // Read the ADC value and scale it to 8-bit value
    // because the ADC is 10-bit (1024 values) and the
    // PWM register is only 8-bit (256 values), 1024/256 = 4
    value = (uint8_t)(ADCW/4);

    // Write the value to the Output Compare Register A
    OCR1A = value;

    // Wait for 2 ms
    _delay_ms(2);
    }

    return 0;
    }
  • 30.08.2009 07:36 gNome^

  • Hi,

    It looks as you define LED in the beginning of the program, but don't use that definition anywhere? Is this because you want to remember where the led in question is, or for a i/o purpose?

    Also you do not do anything for the led other than set it off by defining PORTB = 0x00; And the DDRB register might be better off as 0xFF

    You should check out what the program should do when OCR1x registers match/mismatch.

    This is getting a bit long for a quick response ;)

    // Potentiometer slide at PB2, (ADC1)
    #define POT 2

    This is not really true, but i trust that you have just copied from Aki's code. AtMEGA32 has all 8 pins for ADC, but they are PORTA pins 0-7.

    Also, nothing happens to this define or nothing is done with it.

    I suggest you check the example code again, and then if need be your wirings, but i believe this just to be an error with the adc port.

    bleh, it got all messy, it's 7 AM i'll try to be clearer in the PM hours

    -gN
  • 30.08.2009 19:02 toffie

  • yeah I've noticed that as well, but as I'm not that great with C programming yet I figured that
    some sample code should be correct and should work ;)

    yes I've tried with setting the PORT to A as well from B as those are the ADC pins, that I knew :)
    But it did not do any difference..

    Anyway, the only thing I changed before I posted the code here on the forums was the
    TCCR0A to TCCR1A and COM0A1 to COM1A1, because then it could compile for the ATmega32..
    However, I don't know if that was correct to do and if more should be done to get it to work,
    but perhaps the defines need to be handled as well otherwise the uC dont know where the
    LED and POT are.

    I'm still looking at other examples, while hard to find therefore I tried Aki's code :)
    but I havent found anything out yet.. ;)

    When I finally get some code that works I'll make sure to post it here if someone else
    haven't posted it by then..

    But if someone can see the problem in this code, please feel free to help out! :)
  • 30.08.2009 20:11 gNome^

  • I was trying to direct you in the right direction but it seems we weren't on the same page.

    The problem with the output pin PB2 is that you have set the whole port as 0 with the command PORTB = 0x00;

    This puts PORTB as input and you can't get the VCC value out of it.

    Also, the ADC is reading the potentiometer as it should, it just isn't indicating the results anywhere.

    Here is how you should go about fixing it.

    You have nothing else stuck on PORTB besides the led. (I am assuming here) You can go ahead and set DDRB as 0xFF (1111 1111) then set PORTB as 0x00 (0000 0000). Now you have DDRB (PORTB I/O) register set as output and the led turned off.

    As i see it the defines for LED and POT are totally useless?

    Maybe Aki would like to comment on those.

    I checked the datasheet for ATMEGA32 (i assume you have too) the OC0 pin is at PB3 not PB2 so try as you might the led won't light up at PB2.

    I wish you happy times with µcontrollers and a word of advice. Always check the wiring from the datasheet.

    If you have any questions or my advice is just totally wrong (has been known to happen on more than one occasion) let us know. And keep us posted on your progress

    -gN
  • 30.08.2009 23:25 AK

  • The defines for POT and LED don't actually do anything, I kinda forgot them there as reminders. You can remove those lines if you want to.

    It should be safe to delete these lines too:
    // PB2 in, others out
    DDRB = 0b11011;
    PORTB = 0x00;

    Tiny and mega -chips have slightly different names for registers and if you are porting a code meant for different chip than you are using, you just need to crawl through the datasheets of both of them and look for matching registers and change the code accordingly.

    Here are some replacements I looked up, you seemed to have some of them right, but I'll include them here. Put these in the code and test them out, I don't have my ATmega32 development board at hand right now so I can't test those yet myself.

    TCCR0A -> TCCR1A
    WGM00 -> WGM10
    COM0A1 -> COM1A1
    TCCR0B -> TCCR1B
    CS01 -> CS11

    "The COM1A1:0 and COM1B1:0 control the Output Compare pins (OC1A and OC1B respectively) behavior."

    So if we look at mega32's datasheet, we see that OC1A is at PD5 (port D / bit 5, look for the physical pin from the datasheet).

    Then what comes to the ADC, you'll need to supply 5 volts to the AREF pin on your ATmega32 because it can't use VCC as reference like the ATtiny45 does.

    To avoid too much code changes, let's still use ADC1 and it's located in PA1 (port A / bit 1) on ATmega32.

    So in short:
    1) Replace the registers
    2) Supply 5 volts to AREF
    3) PD5 for OC1A (connect led here)
    4) PA1 for ADC1 (connect potentiometer here)

    In theory the example should work with these instructions, but I can't confirm it right now because my devboard is somewhere.
  • 01.09.2009 02:53 toffie

  • dedicated as I am to problems, when I feel for ;) here are the result of debugging and testing and trying different things ;)
    the schematic should work as before, but I made a new one for how I connected it all..

    Hopefully someone could verify that this works for them as well, on a ATmega32, so that I dont post something that
    I think work, but doesnt work :)

    But it should work as it works perfectly for me now on the ATmega32 :D


    Posting the code here directly as well, added my name to the comment in the top, if that's ok? ;)

    /**
    * MetkuMods - http://metku.net/
    * How to get started with AVR microcontrollers, part 2
    * Example 2.3.1 - Reading the value of a potentiometer
    *
    * Author: Aki Korhonen
    * Date: 2009-04-29
    *
    * Edited by: Chris Fredriksson, this code is for ATmega32
    * Edited date: 2009-09-01
    */

    // If clock speed isn't set in the project settings then it is set here
    #ifndef F_CPU
    #define F_CPU 1000000UL // 1 MHz
    #endif

    #include
    #include

    #include

    int main(void)
    {
    // PD2 in, others out
    DDRD = 0x20;
    PORTD = 0x00;

    // Value for the register, placeholder
    uint8_t value = 0;

    // -------------------------
    // Initialize PWM

    // 8-bit PWM, Phase correct
    // 8 bits give us 256 levels of brightness
    TCCR1A |= (1<
    // Clear OC1A/OC1B on Compare Match
    // Set OC1A/OC1B at BOTTOM (non-inverting mode)
    TCCR1A |= (1<
    // Set prescaler to 8
    // 1 MHz / 8*256 = ~490 Hz PWM frequency
    TCCR1B |= (1<
    // -------------------------
    // Initialize ADC

    // Enable ADC
    ADCSRA = (1<
    // Select ADC0
    ADMUX |= (0<
    // Use Vcc as voltage reference
    ADMUX &= ~(1<
    // Select divider factor 8, so we get 1 MHz/8 = 125 kHz ADC clock
    ADCSRA |= (1<
    // -------------------------

    // The program reads the ADC value from the potentiometer slide
    // all the time and calculates a delay between the steps.
    while(1)
    {
    // Write the value to the Output Compare Register A
    OCR1A = value;

    // what happens here??
    value = (uint8_t)(ADCW/4);

    // Start ADC conversion
    ADCSRA |= (1<
    // Wait until the conversion is ready
    loop_until_bit_is_set(ADCSRA, ADSC);
    }

    return 0;
    }
  • 02.11.2009 23:19 tissit

  • I would suggest testing the 232/233 serial part first. Build the serial level translator (maxim chip) and connect the wires going to the microcontroller TxD/RxD together and not to the mcu. You'll have a loopback circuit. Power it up and connect to that with a terminal program. Anything you type in should come back to you. Once that works, power down and wire the TxD/RxD pins to the mcu. In case something goes wrong, you'll at least know it isn't the level converter.
  • 03.11.2009 01:20 toffie

  • uhm, what are you replying to?
Osallistu keskusteluun. Artikkeliin liittyvä viestiketju foorumissa.


Sivut:  1 2 3 4 5 6 


 
  Content in english!
  Sisältö suomeksi!

 Google




Add to Technorati Favorites
add
add
add
add
add

 .:Back to top Bandwidth by Mpoli

Copyright © Metku.net, All Rights Reserved.
All content and graphics in MetkuMods are sole property of Jani Pönkkö and may not be reproduced or copied in any manner without written permission from him.
All brand names, trademarks and copyrights are the property of their respective owners.Privacy Policy