Programando microcontroladores em C do zero. CodeVisionAVR. Informações gerais para iniciantes em programação na linguagem C. Qual microcontrolador escolher para funcionar

De alguma forma, senti-me imediatamente compelido a aconselhar sobre a escolha de um ambiente de programação para controladores AVR. Só não jogue chinelos em mim. Estou só um pouquinho :)

Existem muitas linguagens de programação para microcontroladores. Existem também alguns ambientes de programação e é incorreto compará-los entre si. Melhores idiomas programação não existe. Isso significa que você terá que escolher a linguagem e o ambiente de programação mais adequados para você.

Se você está atualmente enfrentando uma escolha sobre o que começar a trabalhar, aqui estão algumas recomendações para você.

Experiência anterior em programação. Não negligencie sua experiência anterior em programação. Mesmo que fosse BÁSICO. Mesmo que tenha sido há muito tempo na escola. Programar é como andar de bicicleta – assim que você começa, você rapidamente se lembra de tudo que esqueceu. Comece com o BASIC - domine-o - mais tarde será mais fácil escolher algo mais adequado aos seus propósitos.

Ajuda do meio ambiente. Seus amigos escrevem em Pascal? O problema está resolvido para você - escreva em Pascal! Eles sempre irão ajudá-lo com conselhos, fornecer-lhe bibliotecas e projetos prontos para estudar. Em geral, eles ficarão felizes em recebê-lo em sua comunidade. Se você fizer o oposto, obterá o resultado oposto. Amigos da indústria da CEI irão bicá-lo se você decidir estudar Assembler. Não espere ajuda.

Bom livro em Programação AVR vai ajudar muito. Infelizmente, há muito poucos deles. Se você se deparar com um livro e achar que tudo está explicado de uma forma muito acessível, experimente. Não recomendo estudar com e-books; como último recurso, imprima-os. É muito inconveniente alternar entre o ambiente e o texto do arquivo do livro. É muito mais prazeroso ler um livro e experimentá-lo na hora, sem se distrair com trocas; além disso, você pode fazer anotações nas margens e anotar as ideias que surgirem.

O ambiente de programação é mais simples. Se existem vários ambientes de programação para sua linguagem escolher, não hesite, escolha aquele que for mais simples. Que seja menos funcional. Deixe-a compilar um código terrivelmente inchado. O principal é apenas começar a trabalhar. Depois de se sentir confortável em um ambiente simples, você poderá facilmente migrar para um ambiente mais avançado e “correto”. E não dê ouvidos a quem diz que você perderá mais tempo - eles estão errados. Os alunos da escola primária não são convidados a ler “Guerra e Paz”, mas sim livros mais simples - com imagens.

Bibliotecas. A disponibilidade de bibliotecas é controversa para a aprendizagem de línguas. Claro que mais tarde vão facilitar muito a vida, mas a princípio as bibliotecas “Black Box” são incompreensíveis e não contribuem muito para a compreensão da linguagem. Por outro lado, tornam os programas mais fáceis de ler e permitem que um iniciante construa programas complexos sem muito esforço. Portanto, não se preocupe muito com a presença deles. Pelo menos no começo.

Código eficiente. Escolher um ambiente de programação para aprender programação baseado apenas na eficiência do código que ele compila é uma má ideia. O principal é que você se sinta confortável ao começar a estudar – o que sai disso é a décima coisa. Claro, você pode trabalhar nisso mais tarde.

Feiticeiros. Qualquer dispositivo integrado no chip precisa ser configurado por meio de portas. O procedimento é bastante tedioso e são necessárias folhas de dados. Além disso, existem nuances que não são fáceis de serem compreendidas por um iniciante. Portanto, é muito desejável ter assistentes no ambiente. Vyzards são sintonizadores automáticos para SPI, I2C, USART, etc. Quanto mais dispositivos forem suportados, melhor. Você define os parâmetros periféricos necessários e o próprio assistente gera o código que fornecerá os parâmetros especificados. Torna a vida muito mais fácil.


Recomendações gerais tal - a programação no estágio inicial deve ser o mais simples possível (mesmo primitiva). O ambiente de programação deve ser fácil de aprender (já que você precisa, primeiro, dominar a programação e não perder tempo mexendo nas configurações). De preferência russificado. Um manual russo e programas de exemplo também seriam úteis. A capacidade de remover o cristal do ambiente é desejável. Então, à medida que você domina os fundamentos da programação, você pode passar para shells mais complexos.


Uma última recomendação: trabalhe com um cristal verdadeiro. Não tenha medo de queimá-lo. Ganhe experiência prática. Trabalhar com emuladores (por exemplo Proteus), embora o liberte da preocupação com um ferro de soldar, nunca será capaz de lhe dar a satisfação que obterá com o programa de trabalho e o primeiro piscar do LED! Entender que você fez um diagrama real de trabalho com suas próprias mãos lhe dá confiança e incentivo para seguir em frente!

(Visitado 7.377 vezes, 1 visita hoje)

Olá, querido Habrazhitel!

Neste artigo quero falar sobre como decidi começar a programar microcontroladores, o que foi necessário para isso e o que acabou acontecendo.

O tema microcontroladores me interessou há muito tempo, em 2001. Mas então acabou sendo problemático conseguir um programador na minha residência e não havia como comprá-lo pela Internet. Tive que adiar esse assunto para tempos melhores. E então, um belo dia, descobri que tempos melhores haviam chegado sem sair de casa, poderia comprar tudo que precisasse. Eu decidi tentar. Então, o que precisamos:

1. Programador
Existem muitas opções no mercado - desde os programadores ISP (In-System Programming) mais baratos por alguns dólares, até poderosos programadores-depuradores por algumas centenas. Não tendo muita experiência no assunto, resolvi primeiro experimentar um dos mais simples e baratos - USBasp. Eu comprei no eBay uma vez por US$ 12, agora você pode encontrá-lo por até US$ 3-4. Na verdade, esta é uma versão chinesa do programador de Thomas Fischl. O que posso dizer sobre ele? Só uma coisa: funciona. Além disso, ele suporta vários controladores AVR das séries ATmega e ATtiny. No Linux não requer driver.

Para atualizar o firmware, você precisa conectar as saídas do programador VCC, GND, RESET, SCK, MOSI, MISO às saídas correspondentes do microcontrolador. Para simplificar, montei o circuito auxiliar diretamente na protoboard:

À esquerda da placa está o mesmo microcontrolador que vamos atualizar.

2. Microcontrolador
Não me preocupei muito com a escolha do microcontrolador e peguei o ATmega8 da Atmel - 23 pinos de I/O, dois temporizadores de 8 bits, um de 16 bits, frequência de até 16 MHz, baixo consumo (1-3,6 mA) , barato (US$ 2). Em geral, para começar, é mais que suficiente.

No Linux, a combinação avr-gcc + avrdude funciona bem para compilar e carregar firmware no controlador. A instalação é trivial. Seguindo as instruções, você pode instalar todo o software necessário em poucos minutos. A única ressalva que você deve prestar atenção é que o avrdude (software para gravação no controlador) pode exigir direitos de superusuário para acessar o programador. A solução é executá-lo via sudo (não é uma boa ideia) ou registrar direitos especiais do udev. A sintaxe pode diferir em diferentes versões do sistema operacional, mas no meu caso ( Linux Mint 15) adicionar a seguinte regra ao arquivo /etc/udev/rules.d/41-atmega.rules funcionou:

# Programador USBasp SUBSYSTEM=="usb", ATTR(idVendor)=="16c0", ATTR(idProduct)=="05dc", GROUP="plugdev", MODE="0666"

Depois disso, é claro, você precisa reiniciar o serviço
serviço udev reiniciar
Você pode compilar e atualizar sem problemas diretamente do linha de comando(quem duvidaria), mas se houver muitos projetos, então é mais conveniente instalar um plugin e fazer tudo diretamente do ambiente Eclipse.

Para Windows você terá que instalar um driver. Caso contrário, não há problemas. Por uma questão de interesse científico, experimentei a combinação AVR Studio + eXtreme Burner no Windows. Novamente, tudo funciona muito bem.

Vamos começar a programar

Os controladores AVR podem ser programados tanto em assembler (AVR assembler) quanto em C. Aqui, penso eu, cada um deveria fazer sua própria escolha dependendo da tarefa específica e de suas preferências. Pessoalmente, comecei a mexer com assembler. Ao programar em assembler, a arquitetura do dispositivo fica mais clara e você tem a sensação de que está mergulhando diretamente no interior do controlador. Além disso, acredito que em programas particularmente críticos em tamanho e desempenho, o conhecimento de assembler pode ser muito útil. Depois de me familiarizar com o montador AVR, rastejei até C.

Depois de conhecer a arquitetura e os princípios básicos, decidi montar algo útil e interessante. Aqui minha filha me ajudou, ela joga xadrez e uma bela noite disse que queria um cronômetro para jogos cronometrados. BAM! Aqui está - a ideia do primeiro projeto! Você poderia, é claro, encomendá-los no eBay, mas eu queria fazer meu próprio relógio, com... uh... indicadores e botões pretos. Dito e feito!

Decidiu-se usar dois indicadores de diodo de 7 segmentos como display. Para o controle bastaram 5 botões - “Player 1”, “Player 2”, “Reset”, “Settings” e “Pause”. Bem, não se esqueça da indicação sonora do final do jogo. Parece que é isso. A figura abaixo mostra um diagrama geral de conexão do microcontrolador a indicadores e botões. Precisaremos dele ao analisar o código-fonte do programa:

Interrogatório

Vamos começar, como esperado, do ponto de entrada do programa - a função principal. Na verdade, não há nada de notável nisso - configuração de portas, inicialização de dados e um ciclo interminável de pressionamento de botões de processamento. Bem, chamando sei() - habilitando o processamento de interrupções, falaremos mais sobre elas um pouco mais tarde.

Int main(void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) return 0; )
Vejamos cada função separadamente.

Void init_io() ( // define a saída DDRB = 0xFF; DDRD = 0xFF; // define a entrada DDRC = 0b11100000; // resistores pull-up PORTC |= 0b00011111; // interrupções do temporizador TIMSK = (1<

Configurar portas de E/S é muito simples - um número é escrito no registro DDRx (onde x é a letra que designa a porta), cada bit significa se o pino correspondente será um dispositivo de entrada (corresponde a 0) ou um dispositivo de saída (corresponde a 1). Assim, ao enviar o número 0xFF para DDRB e DDRD, criamos portas de saída B e D. Assim, o comando DDRC = 0b11100000; transforma os primeiros 5 pinos da porta C em pinos de entrada e os restantes em pinos de saída. Comando PORTC |= 0b00011111; inclui resistores pull-up internos em 5 entradas do controlador. De acordo com o diagrama, botões são conectados a essas entradas, que, ao serem pressionados, causam curto-circuito no aterramento. Desta forma o controlador entende que o botão está pressionado.

Em seguida vem a configuração de dois temporizadores, Timer0 e Timer1. Utilizamos o primeiro para atualizar os indicadores, e o segundo para fazer a contagem regressiva do tempo, previamente configurado para disparar a cada segundo. Uma descrição detalhada de todas as constantes e o método para definir o temporizador para um intervalo específico pode ser encontrada na documentação do ATmega8.

Tratamento de interrupções

ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 0) process_timeoff(); ) )

Quando o temporizador é acionado, o controle é transferido para o manipulador de interrupção apropriado. No nosso caso, este é o manipulador TIMER0_OVF_vect, que chama o procedimento de exibição do tempo nos indicadores, e TIMER1_COMPA_vect, que processa a contagem regressiva.

Resultado para indicadores

Void display() ( display_number((Timer1/60)/10, 0b00001000); _delay_ms(0,25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0,25); display_number((Timer1%60)/10 , 0b00000010); _delay_ms(0,25); display_number((Timer1%60)%10, 0b00000001); _delay_ms(0,25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0,25); display_number((Timer2/ 60)%10, 0b01000000); _delay_ms(0,25); display_number((Timer2%60)/10, 0b00100000); _delay_ms(0,25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0,25); PORTD = 0; ) void display_number(int número, int máscara) ( PORTB = número_mask(número); PORTD = máscara; )

A função de exibição usa um método de exibição dinâmico. O fato é que cada indicador individual possui 9 contatos (7 para controle de segmento, 1 para ponto e 1 para potência). Para controlar 4 dígitos seriam necessários 36 contatos. Muito desperdício. Portanto, a saída de dígitos para um indicador com vários dígitos é organizada de acordo com o seguinte princípio:

A tensão é fornecida alternadamente a cada um dos contatos comuns, o que permite destacar o número desejado no indicador correspondente usando os mesmos 8 contatos de controle. Em uma frequência de saída alta o suficiente, parece uma imagem estática aos olhos. É por isso que todos os 8 contatos de potência de ambos os indicadores no diagrama estão conectados às 8 saídas da porta D, e 16 contatos de controle de segmento são conectados em pares e conectados às 8 saídas da porta B. Assim, o display funciona com um atraso de 0,25 ms exibe alternadamente o número desejado em cada um dos indicadores. Por fim, todas as saídas que fornecem tensão aos indicadores são desligadas (comando PORTD = 0;). Se isso não for feito, o último dígito exibido continuará aceso até a próxima chamada da função de display, o que fará com que seu brilho seja mais brilhante em comparação com os demais.

Tratamento de cliques

Void handle_buttons() ( handle_button(KEY_SETUP); handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void handle_button(int key) ( int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; break; padrão: return; ) if (bit_is_clear( BUTTON_PIN, bit)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= key; // chave de ação switch (key) ( case KEY_SETUP: process_setup(); break; case KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) else ( _pressed &= ~chave; ) )

Esta função pesquisa todos os 5 botões por vez e processa o clique, se houver. O clique é registrado verificando bit_is_clear(BUTTON_PIN, bit) , ou seja, o botão é pressionado se a entrada correspondente estiver conectada ao terra, o que acontecerá, conforme diagrama, quando o botão for pressionado. Um atraso de duração DEBOUNCE_TIME e verificação repetida são necessários para evitar múltiplas operações desnecessárias devido à rejeição do contato. Salvar o status pressionado nos bits correspondentes da variável _pressed é usado para evitar acionamentos repetidos quando o botão é pressionado por um longo tempo.
As funções de processamento de cliques são bastante triviais e acredito que dispensam comentários adicionais.

Texto completo do programa

#define F_CPU 4000000UL #include #incluir #incluir #define DEBOUNCE_TIME 20 #define BUTTON_PIN PINC #define SETUP_BIT PC0 #define RESET_BIT PC1 #define PAUSE_BIT PC2 #define PLAYER1_BIT PC3 #define PLAYER2_BIT PC4 #define KEY_SETUP 0b00000001 #define KEY_RESET 0b0000001 0 #define KEY _PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 volátil int ActiveTimer = 0; volátil int Temporizador1 = 0; volátil int Temporizador2 = 0; volátil int _buzzer = 0; volátil int _pressionado = 0; // declarações de função void init_io(); void init_data(); int número_máscara(int num); void handle_buttons(); void handle_button (chave int); void process_setup(); void process_reset(); void process_pause(); void process_timeoff(); void process_player1(); void process_player2(); exibição nula(); void display_number(int máscara, int número); void sound_on (intervalo interno); void sound_off(); // interrompe ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) (Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) (Timer2--; if (Timer2 == 0) process_timeoff(); ) ) int main (void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) return 0; ) void init_io() ( // define a saída DDRB = 0xFF; DDRD = 0xFF ; // configura a entrada DDRC = 0b11100000; // resistores pull-up PORTC |= 0b00011111; // temporizador interrompe TIMSK = (1<5940 || Timer2 > 5940) ( Timer1 = 0; Timer2 = 0; ) ) void process_reset() ( init_data(); ) void process_timeoff() ( init_data(); sound_on(30); ) void process_pause() ( ActiveTimer = 0; ) void process_player1() ( ActiveTimer = 2; ) void process_player2() ( ActiveTimer = 1; ) void handle_button(int key) ( int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT ; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; break; padrão: return; ) if (bit_is_clear(BUTTON_PIN, bit)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= key; // chave de ação switch (key) ( case KEY_SETUP: process_setup(); break; case KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) else ( _pressed &= ~key; ) ) void handle_buttons() ( handle_button(KEY_SETUP); handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void display() ( display_number((Timer1/60)/10, 0b00001000) ; _delay_ms(0,25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0,25); display_number((Timer1%60)/10, 0b00000010); _delay_ms(0,25); display_number((Timer1%60)% 10, 0b00000001); _delay_ms(0,25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0,25); display_number((Timer2/60)%10, 0b01000000); _delay_ms(0,25); display_number((Timer2 %60)/10, 0b00100000); _delay_ms(0,25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0,25); PORTD = 0; ) void display_number(int número, int máscara) ( PORTB = number_mask (número); PORTD = máscara; ) void sound_on(int interval) ( _buzzer = interval; // coloca o pino da campainha alto PORTC |= 0b00100000; ) void sound_off() ( // coloca o pino da campainha baixo PORTC &= ~0b00100000; )

O protótipo foi montado em uma protoboard.

Lição 0.

Então, hoje abrimos uma série de aulas sobre programação de microcontroladores da família AVR.

Hoje serão discutidas as seguintes questões:

  1. O que é um microcontrolador?
  2. Onde os microcontroladores são usados?

Introdução.

Os microcontroladores estão por toda parte. Em telefones, máquinas de lavar, “casas inteligentes”, máquinas-ferramentas em fábricas e também em inúmeros outros dispositivos técnicos. Seu uso generalizado permite substituir circuitos analógicos complexos por circuitos digitais mais compactados.

Então, o que é um microcontrolador?

Microcontrolador (Unidade de microcontrolador, MCU) - um microcircuito projetado para controlar dispositivos eletrônicos. Você pode imaginá-lo como um computador simples capaz de interagir com dispositivos externos. Por exemplo, abrindo e fechando transistores, recebendo dados de sensores de temperatura, exibindo dados em telas LCD, etc. Além disso, o microcontrolador pode realizar diversos processamentos de dados de entrada, assim como o seu computador pessoal.

Ou seja, os microcontroladores oferecem-nos possibilidades quase ilimitadas de controlo de quaisquer dispositivos, graças à presença de portas I/0 (portas de entrada/saída), bem como à possibilidade de os programar.

Onde os microcontroladores são usados?

  1. Eletrodomésticos (Máquinas de lavar roupa, fornos microondas, etc.).
  2. Tecnologia móvel (robôs, sistemas robóticos, equipamentos de comunicação, etc.).
  3. Equipamentos industriais (sistemas de controle de máquinas).
  4. Tecnologia informática (placas-mãe, sistemas de controle de dispositivos periféricos).
  5. Equipamentos de entretenimento (brinquedos infantis, decorações).
  6. Transporte (sistemas de controle de motores de automóveis, sistemas de segurança)

Esta não é uma lista completa de aplicações para microcontroladores. Freqüentemente, é muito lucrativo substituir um conjunto de chips de controle por um microcontrolador, devido à produção simplificada e ao consumo reduzido de energia.

Introdução ao AVR

AVR- uma família de microcontroladores da Atmel, com desempenho suficiente para a maioria dos dispositivos amadores. Eles também são amplamente utilizados na indústria.

Existem várias linguagens de programação para microcontroladores AVR, mas talvez as mais adequadas sejam assembler e C, uma vez que essas linguagens implementam melhor todos os recursos necessários para gerenciar o hardware do microcontrolador.

A linguagem assembly é uma linguagem de programação de baixo nível que usa o conjunto de instruções diretas do microcontrolador. Criar um programa nesta linguagem requer um bom conhecimento do sistema de comando do chip programável e tempo suficiente para desenvolver o programa. A linguagem assembly é inferior a C em velocidade e facilidade de desenvolvimento de programas, mas tem vantagens notáveis ​​​​no tamanho do código executável final e, consequentemente, na velocidade de sua execução.

C permite criar programas com muito mais conforto, proporcionando ao desenvolvedor todos os benefícios de uma linguagem de alto nível.
Ressalta-se mais uma vez que a arquitetura e o sistema de comando do AVR foram criados com a participação direta dos desenvolvedores do compilador da linguagem C e leva em consideração as características desta linguagem. A compilação do código-fonte C é rápida e produz código compacto e eficiente.

As principais vantagens do C sobre o assembler: alta velocidade de desenvolvimento de programas; universalidade que dispensa um estudo aprofundado da arquitetura do microcontrolador; melhor documentabilidade e legibilidade do algoritmo; disponibilidade de bibliotecas de funções; suporte para cálculos de ponto flutuante.

A linguagem C combina harmoniosamente capacidades de programação de baixo nível com as propriedades de uma linguagem de alto nível. A capacidade de programação de baixo nível permite operar facilmente diretamente no hardware, e as propriedades da linguagem de alto nível permitem criar código de programa facilmente legível e modificável. Além disso, quase todos os compiladores C têm a capacidade de usar inserções em assembler para escrever seções de programa que são críticas em termos de tempo de execução e consumo de recursos.

Em uma palavra, C é a linguagem mais conveniente tanto para iniciantes que se familiarizam com microcontroladores AVR quanto para desenvolvedores sérios.

Compiladores são usados ​​para converter o código-fonte de um programa em um arquivo de firmware de microcontrolador.

Atmel fornece um compilador assembly poderoso que está incluído no ambiente de desenvolvimento Atmel Studio em execução no Windows. Junto com o compilador, o ambiente de desenvolvimento contém um depurador e um emulador.
Atmel Studio é totalmente gratuito e está disponível no site da Atmel.

Atualmente, existem muitos compiladores C para AVR. O mais poderoso deles é considerado o compilador da IAR Systems de Estocolmo. Foram seus funcionários que participaram do desenvolvimento do sistema de comando AVR em meados dos anos 90. O IAR C Compiler possui amplos recursos de otimização de código e vem como parte do ambiente de desenvolvimento integrado IAR Embedded Workbench (EWB), que também inclui um compilador assembler, vinculador, gerenciador de projeto e biblioteca e depurador. O preço da versão completa do pacote é 2.820 EUR. No site da empresa você pode baixar uma versão de avaliação gratuita por 30 dias ou uma versão ilimitada com limite de tamanho de código de 4 KB.

A empresa americana Image Craft de Palo Alto, Califórnia, produz um compilador de linguagem C que ganhou grande popularidade. JumpStart C para AVR tem otimização de código aceitável e um preço não muito alto (de US$ 50 a US$ 499 dependendo da versão). A versão demo do JumpStart C para AVR é ​​totalmente funcional por 45 dias.

O compilador Romeno Code Vision AVR C não ganhou menos popularidade: o preço da versão completa deste compilador é relativamente baixo e chega a 150 EUR. O compilador vem com um ambiente de desenvolvimento integrado, que, além dos recursos padrão, inclui um recurso bastante interessante - CodeWizardAVR Automatic Program Generator. A presença de um terminal serial no ambiente de desenvolvimento permite depurar programas usando a porta serial do microcontrolador. Você pode baixar uma versão de avaliação gratuita dos desenvolvedores com um limite de tamanho de código de 4 KB e salvamento desabilitado do código-fonte gerado em C.

A empresa MikroElektronika, localizada na cidade sérvia de Belgrado, produz toda uma família de compiladores para microcontroladores AVR. Um compilador para a linguagem C chamado mikroC PRO para AVR custa US$ 249. Existem também mikroBasic e mikroPascal pelo mesmo preço. Existem versões demo no site dos desenvolvedores com um limite de tamanho de código de 4.096 bytes. A vantagem desta família de compiladores é uma plataforma única e uma ideologia única, que pode proporcionar uma transição fácil não só entre linguagens, mas também entre microcontroladores (existem versões de compiladores para PIC, STM32, 8051...).

O ambiente de desenvolvimento integrado tornou-se verdadeiramente icônico. Inclui poderosos compiladores C e assembler, o programador AVRDUDE, um depurador, um simulador e muitos outros programas e utilitários de suporte. WinAVR integra-se perfeitamente com o ambiente de desenvolvimento AVR Studio da Atmel. O assembler é idêntico em código de entrada ao assembler do AVR Studio. Os compiladores C e assembler têm a capacidade de criar arquivos de depuração no formato COFF, o que permite usar não apenas ferramentas integradas, mas também o poderoso simulador AVR Studio. Outra vantagem importante é que o WinAVR é ​​distribuído gratuitamente e sem restrições (os fabricantes suportam a Licença Pública Geral GNU).

Resumindo, vale dizer que WinAVR é ​​a escolha ideal para quem está começando a dominar os microcontroladores AVR. É este ambiente de desenvolvimento que é considerado o principal neste curso.

Kiselev Roman, maio de 2007 Artigo atualizado em 26 de maio de 2014

Então, o que é um microcontrolador (doravante denominado MK)? Este é, relativamente falando, um pequeno computador alojado num único circuito integrado. Possui um processador (unidade lógica aritmética ou ALU), memória flash, memória EEPROM, muitos registros, portas de E/S, bem como sinos e assobios adicionais, como temporizadores, contadores, comparadores, USARTs, etc. , o microcontrolador inicializa e começa a executar o programa armazenado em sua memória flash. Ao mesmo tempo, pode controlar uma ampla variedade de dispositivos externos através de portas de E/S.

O que isto significa? Isso significa que no MK você pode implementar qualquer circuito lógico que irá executar determinadas funções. Isso significa que o MK é um microcircuito, cujo conteúdo interno, na verdade, nós mesmos criamos. Isso permite, tendo comprado vários MKs completamente idênticos, montar neles circuitos e dispositivos completamente diferentes. Se quiser fazer alguma alteração no funcionamento de um aparelho eletrônico, não será necessário usar ferro de solda, basta reprogramar o MK. Nesse caso, você nem precisa removê-lo do seu aparelho se estiver usando um AVR, já que esses MKs suportam programação em circuito. Assim, os microcontroladores preenchem a lacuna entre a programação e a eletrônica.

AVRs são microcontroladores de 8 bits, ou seja, sua ALU pode realizar operações simples com apenas números de 8 bits em um ciclo de clock. Agora é hora de falar sobre qual MK usaremos. Estou trabalhando com um ATMega16 MK. É muito comum e pode ser comprado em quase todas as lojas de peças de rádio por cerca de 100 rublos. Se não encontrar, você pode comprar qualquer outro MK da série MEGA, mas neste caso você terá que procurar documentação para isso, já que as mesmas “pernas” de diferentes MKs podem desempenhar funções diferentes, e por conectando, ao que parece, se todas as conclusões estiverem corretas, você poderá obter um dispositivo funcionando ou talvez apenas uma nuvem de fumaça fedorenta. Ao adquirir um ATMega16, certifique-se de que ele vem em um pacote DIP grande de 40 pinos e compre também um soquete para ele no qual possa ser inserido. Para trabalhar com ele, você também precisará de dispositivos adicionais: LEDs, botões, conectores, etc.

ATMega16 possui um grande número de funções diversas. Aqui estão algumas de suas características:

  • Frequência máxima de clock – 16 MHz (8 MHz para ATMega16L)
  • A maioria dos comandos são executados em um ciclo de clock
  • 32 registros de trabalho de 8 bits
  • 4 portas de E/S completas de 8 bits
  • dois contadores/temporizadores de 8 bits e um de 16 bits
  • Conversor analógico-digital (ADC) de 10 bits
  • gerador de clock interno a 1 MHz
  • comparador analógico
  • interfaces SPI, I2C, TWI, RS-232, JTAG
  • programação em circuito e autoprogramação
  • módulo de modulação por largura de pulso (PWM)

As características completas deste dispositivo, bem como as instruções de uso, podem ser encontradas no livro de referência (Ficha Técnica) deste MK. É verdade que está em inglês. Se você sabe inglês, não deixe de baixar esta Ficha Técnica, ela contém muitas informações úteis.

Vamos finalmente começar a trabalhar. Recomendo fazer uma placa especial de desenvolvimento e depuração para o microcontrolador, na qual você pode montar qualquer circuito elétrico com microcontrolador sem ferro de solda (ou quase sem ele). A utilização de tal placa facilitará muito o trabalho com o MK e agilizará o processo de aprendizado de sua programação. Se parece com isso:

O que você precisará para isso?

Primeiro, você precisará da própria placa. Comprei um pronto em uma loja de peças de rádio por 115 rublos. Então soldei todas as peças necessárias nele. O resultado é algo incrivelmente prático, no qual você pode montar qualquer circuito elétrico em questão de minutos, conectando cabos e instalando microcircuitos e indicadores.

Para conectar elementos do circuito, é muito conveniente usar cabos com conectores nas extremidades. Esses conectores são colocados nas “pernas” que ficam próximas a cada porta do MK. O microcontrolador deve ser instalado no soquete e não soldado na placa, caso contrário será muito difícil removê-lo se você queimá-lo acidentalmente. Abaixo está a pinagem do ATMEGA16 MK:

Vamos explicar em quais pernas estamos interessados ​​​​agora.

  • VCC - a alimentação é fornecida aqui (4,5 - 5,5 V) de uma fonte estabilizada
  • GND – terra
  • RESET – reset (em nível de baixa tensão)
  • XTAL1, XTAL2 – um ressonador de quartzo está conectado aqui
  • PA, PB, PC, PD – portas de entrada/saída (A, B, C e D, respectivamente).

Qualquer coisa que produza 7-11 V DC pode ser usada como fonte de energia. Para operação estável do MK, é necessária uma fonte de alimentação estabilizada. Como estabilizador, você pode usar microcircuitos da série 7805. São estabilizadores lineares integrados, cuja entrada é fornecida com 7-11 V de corrente contínua não estabilizada e a saída é de 5 V de corrente estabilizada. Antes e depois do 7805, é necessário instalar capacitores de filtro (eletrolítico para filtrar interferências de baixa frequência e cerâmicos para alta frequência). Se você não conseguir encontrar um estabilizador, poderá usar como fonte de alimentação uma bateria de 4,5 V. O MK deve ser alimentado diretamente a partir dele.

Abaixo está um diagrama da conexão MK:

Vamos agora descobrir o que está aqui.

BQ1 é um ressonador de quartzo que define a frequência operacional do MK. Você pode definir qualquer até 16 MHz, mas como planejamos trabalhar no futuro com uma porta COM, recomendo usar ressonadores para as seguintes frequências: 14,7456 MHz, 11,0592 MHz, 7,3725 MHz, 3,6864 MHz ou 1,8432 MHz (mais tarde ficará claro o porquê). Usei 11,0592 MHz. É claro que quanto maior a frequência, maior será a velocidade do dispositivo.

R1 é um resistor pull-up que mantém uma tensão de 5 V na entrada RESET. Um nível de tensão baixo nesta entrada indica um reset. Após o reset, o MK inicializa (10 - 15 ms) e começa a executar o programa novamente. Por se tratar de uma entrada de alta impedância, você não pode deixá-la “pendurada no ar” - um pequeno pickup nela levará a um reset inesperado do MK. É exatamente para isso que serve o R1. Para maior confiabilidade, também recomendo instalar o capacitor C6 (não mais que 20 µF).

SB1 – botão de reinicialização.

O ressonador de quartzo e o capacitor de filtro C3 devem estar localizados o mais próximo possível do MK (não mais que 5-7 cm), caso contrário podem ocorrer interferências nos fios, levando ao mau funcionamento do MK.

O retângulo azul no diagrama descreve o próprio programador. É conveniente fazê-lo em forma de fio, com uma extremidade conectada à porta LPT e a outra a um determinado conector próximo ao MK. O fio não deve ser excessivamente longo. Se surgirem problemas com este cabo (geralmente não, mas tudo pode acontecer), você terá que soldar o adaptador Altera ByteBlaster. Como fazer isso está escrito na descrição do programador AVReal.

Agora que lidamos com o hardware, é hora de passar para o software.

Existem vários ambientes de desenvolvimento para programação AVR. Em primeiro lugar, este é o AVR Studio - o sistema de programação oficial da Atmel. Ele permite que você escreva em assembler e depure programas escritos em assembly, C e C++. IAR é um sistema de programação comercial em C, C++ e linguagem assembly. WinAVR é ​​um compilador de código aberto. AtmanAVR é ​​um sistema de programação para AVR com uma interface quase exatamente igual ao Visual C++ 6. AtmanAVR também permite depurar programas e contém muitas funções auxiliares que facilitam a escrita de código. Este sistema de programação é comercial, mas, de acordo com a licença, você pode utilizá-lo gratuitamente por um mês.

Sugiro começar a trabalhar com o IAR como o ambiente de desenvolvimento mais transparente. No IAR, um projeto é criado inteiramente à mão, portanto, tendo concluído vários projetos, você já saberá claramente o que significa cada linha de código e o que acontecerá se você alterá-la. Ao trabalhar com AtmanAVR, você terá que usar um modelo pré-criado, que é muito complicado e difícil de entender para uma pessoa sem experiência, ou terá muitos problemas com arquivos de cabeçalho ao montar o projeto do zero. Tendo tratado do IAR, examinaremos posteriormente outros compiladores.

Então, primeiro, obtenha algum IAR. É muito comum e encontrá-lo não deve ser um problema. Depois de baixar o IAR 3.20 de algum lugar, instale o compilador/ambiente de trabalho e execute-o. Depois disso você pode começar a trabalhar.

Após iniciar o IAR, selecione arquivo/novo/espaço de trabalho, selecione o caminho para o nosso projeto e crie uma pasta para ele e dê um nome a ele, por exemplo, “Prog1”. Agora vamos criar um projeto: Projeto / Criar novo projeto… Vamos também chamá-lo de “Prog1”. Clique com o botão direito no título do projeto na árvore do projeto e selecione “Opções”

Aqui iremos configurar o compilador para um MK específico. Primeiro, você precisa selecionar o tipo de processador ATMega16 na guia Target, marcar a caixa de seleção Habilitar definições de bits em arquivos de inclusão de E/S na guia Configuração da biblioteca (para que você possa usar os nomes de bits de vários registradores MK no código do programa ) e selecione o tipo de biblioteca C /EU++. Na categoria ICCAVR, você precisa marcar a caixa de seleção Habilitar suporte multibyte na guia Idioma e desativar a otimização na guia Otimização (caso contrário, isso arruinará nosso primeiro programa).

Em seguida, selecione a categoria XLINK. Aqui você precisa determinar o formato do arquivo compilado. Como agora estamos definindo opções para o modo de depuração, conforme descrito no título, precisamos obter um arquivo de depuração como saída. Posteriormente iremos abri-lo no AVR Studio. Para fazer isso, você precisa selecionar a extensão.cof, e o tipo de arquivo é ubrof 7.

Agora clique em OK e altere Debug para Release.

Vá para Opções novamente, onde todos os parâmetros, exceto XLINK, são definidos da mesma forma. No XLINK, altere a extensão para .hex e o formato do arquivo para intel-standart.

Isso é tudo. Agora você pode começar a escrever seu primeiro programa. Crie uma nova fonte/texto e insira o seguinte código nela:

#incluir"iom16.h" short unsigned int i; vazio principal( vazio) (DDRB = 255; PORTB = 0; enquanto(1) { se(PORTB == 255) PORTB = 0; outro PORTB++; para(eu = 0; eu

O arquivo "iom16.h" está localizado na pasta (C:\Arquivos de programas)\IAR Systems\Embedded Workbench 3.2\avr\inc. Se você estiver usando outro MK, por exemplo, ATMega64, selecione o arquivo “iom64.h”. Esses arquivos de cabeçalho armazenam informações sobre o MK: os nomes dos registradores, bits nos registradores e os nomes das interrupções. Cada pino individual da porta A, B, C ou D pode atuar como entrada ou saída. Isso é determinado pelo Data Direction Register (DDR). 1 torna a perna uma saída, 0 uma entrada. Assim, definindo, por exemplo, DDRA = 13, fazemos as “pernas” PB0, PB2, PB3 saídas, o resto - entradas, porque 13 em binário é 00001101.

PORTB é um registrador que determina o estado dos pinos da porta. Depois de escrever 0 lá, definimos a tensão em todas as saídas para 0 V. Então há um loop infinito. Ao programar o MK, eles sempre fazem um loop infinito em que o MK realiza alguma ação até ser zerado ou até ocorrer uma interrupção. Neste ciclo eles escrevem, por assim dizer, “código de fundo”, que o MK executa por último. Isto poderia ser, por exemplo, a exibição de informações em um display. No nosso caso, o conteúdo do registo PORTB é aumentado até ficar cheio. Depois disso tudo começa de novo. Finalmente, um ciclo for de dez mil ciclos. É necessário formar um atraso visível na mudança do estado da porta B.



Agora salvamos este arquivo na pasta do projeto como Prog1.c, copiamos o arquivo iom16.h para a pasta do projeto, selecionamos Project/Add Files e adicionamos “iom16.h” e “Prog1.c”. Selecione Release, pressione F7, o programa compila e a mensagem deverá aparecer:


Número total de erros: 0
Número total de avisos: 0

Aqui está uma foto do meu programador:

Baixe o programador AVReal. Copie-o (AVReal32.exe) para a pasta Release/exe, onde o arquivo Prog1.hex deve estar localizado. Fornecemos energia ao MK, conectamos o cabo de programação. Abra o Far Manager (é mais conveniente fazer o flash do MK), vá para esta pasta e pressione Ctrl+O. Como temos um MK completamente novo, enchemos

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

Não se esqueça de inserir a frequência correta se não estiver usando 11059200 Hz! Ao mesmo tempo, o chamado fusíveis – registros que controlam seu funcionamento (uso de gerador interno, Jtag, etc.). Depois disso, está pronto para receber o primeiro programa. O programador recebe como parâmetros a porta LPT usada, a frequência, o nome do arquivo e outros (todos eles estão listados na descrição do AVReal). Nós discamos:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

Se a conexão estiver correta, o programador reportará uma programação bem-sucedida. Não há garantia de que isso funcionará na primeira vez (na primeira vez que você chamar o programa). Eu mesmo às vezes sou programado pela segunda vez. Talvez a porta LPT esteja com defeito ou haja interferência no cabo. Se ocorrerem problemas, verifique cuidadosamente o seu cabo. Pela minha própria experiência, sei que 60% das avarias estão associadas à falta de contacto no local certo, 20% à presença de um desnecessário e outros 15% à soldadura errada da coisa errada na coisa errada. Se tudo mais falhar, leia a descrição do programador e tente construir o Byte Blaster.

Vamos supor que tudo funcione para você. Se você agora conectar oito LEDs à porta B do MK (faça isso com o MK desligado, e é aconselhável incluir resistores de 300-400 Ohm em série com os LEDs) e aplicar energia, um pequeno milagre acontecerá - um “ onda” irá passar por eles!

© Kiselev Roman
Maio de 2007


Principal