Как позвонить микроконтроллер

Интерес к GSM модулям возникает когда появляется потребность в удаленном управлении каким либо устройством. GSM модуль может выполнять все те же действия, какие может производить сотовый телефон: совершение и прием звонков, передача/прием SMS, соединение с интернетом при помощи технологии GPRS и т.п. Также к данному модулю можно подсоединить микрофон и громкоговоритель и совершать с его помощью мобильные звонки (на сотовые телефоны). Это открывает возможность к множеству интересных проектов, которые можно осуществить с помощью микроконтроллеров. В этой статье мы рассмотрим подключение и взаимодействие GSM модуля (SIM900A) с микроконтроллером ATmega16 (семейство AVR). На собранной конструкции будет продемонстрирована прием и передача сообщений с помощью GSM модуля.

Подключение GSM модуля к микроконтроллеру AVR ATmega16: внешний вид

Необходимые компоненты

Аппаратное обеспечение

  1. Микроконтроллер ATmega16 (купить на AliExpress).
  2. GSM модуль (SIM900 или любой другой) (купить на AliExpress).
  3. Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
  4. Адаптер на 12В.
  5. JHD_162ALCD (ЖК дисплей 16×2) (купить на AliExpress).
  6. Кнопки.
  7. Резисторы 10 кОм (купить на AliExpress).
  8. Потенциометр (купить на AliExpress).
  9. 10 пиновый FRC кабель.
  10. Источник питания с напряжением 5 Вольт

Программное обеспечение

CodeVisionAVR (или другое подобное, например, Atmel Studio)
SinaProg – для загрузки программы в микроконтроллер ATmega8 с помощью программатора USBASP. Можно использовать и другую аналогичную программу.

GSM модуль можно использовать даже без микроконтроллера, используя для управления им набор команд управления модемом (AT commands). Как показано на приведенном рисунке GSM модуль имеет в своем составе адаптер последовательного синхронного/асинхронного порта (USART), поэтому он может быть напрямую соединен с компьютером при помощи модуля MAX232. А с использованием контактов Tx (передача) и Rx (прием) его можно подсоединить к микроконтроллеру. Также на плате GSM модуля вы можете видеть другие контакты, такие как MIC+, MIC-, SP+, SP- которые используются для подключения микрофона или громокоговорителя. GSM модуль можно запитать с помощью адаптера на 12В используя разъем для постоянного тока.

Внешний вид GSM модуля

Вставьте вашу SIM карту в соответствующий слот модуля и подайте питание, при этом на плате должен загореться светодиод, свидетельствующий о подаче питания. Потом подождите минуту или чуть больше, вы увидите как красный (может использоваться и другой цвет) светодиод будет мигать каждые 3 секунды. Это будет означать что ваш модуль готов к установлению соединения используя вашу SIM карту. После этого вы можете подсоединить к нему сотовый телефон или микроконтроллер.

Управление GSM модулем с использованием набора команд управления модемом (AT commands)

Управлять GSM модулем можно единственным способом – используя набор команд управления модемом (AT commands). К примеру, если вы хотите узнать активен ли ваш GSM модуль вы передаете на него команду “AT” и модуль должен ответить на нее “OK”.

Весь список команд управления модемом (AT commands) можно найти в соответствующих справочниках (он весьма обширен), здесь же в нижеприведенной таблице вы можете увидеть наиболее часто используемые (востребованные) из этих команд.

AT В ответ на эту команду передается OK для подтверждения того что модуль готов к работе
AT+CPIN? Проверить качество сигнала
AT+COPS? Найти имя провайдера услуг
ATD96XXXXXXXX; Звонок на определенный номер
ATA Ответить на входящий звонок
ATH Завершить текущий входящий звонок
AT+COLP Показать номер входящего звонка
AT+VTS=(number) Передать DTMF код. Вы можете использовать любое число на вашей мобильной клавиатуре (кейпаде)
AT+CMGR AT+CMGR=1 Прочесть сообщение на первой позиции
AT+CMGD=1 Удалить сообщение на первой позиции
AT+CMGDA=”DEL ALL” Удалить все сообщения с SIM карты
AT+CMGL=”ALL” Прочесть все сообщения с SIM карты
AT+CMGF=1 Установить SMS конфигурацию. “1” для установки текстового режима.
AT+CMGS = “+91 968837XXXX”
>Any Text<Ctrl+z>
Передает SMS на определенный номер — 968837XXXX. Когда увидите “>” начинайте набирать текст. Нажмите Ctrl+Z чтобы передать текст
AT+CGATT? Проверить интернет соединение на SIM карте
AT+CIPSHUT Закрыть TCP соединение, то есть отключиться от интернета
AT+CSTT = “APN”,”username”,”Pass” Соединиться по GPRS используя ваш APN и пароль (Pass key). Их можно получить от вашего сотового оператора.
AT+CIICR Проверить имеется ли на вашей SIM карте пакет данных
AT+CIFSR Получить IP адрес сети вашей SIM карты
AT+CIPSTART = “TCP”,”SERVER IP”,”PORT” Установить соединение TCP IP
AT+CIPSEND Эта команда используется чтобы передать данные на сервер

Для нашей схемы мы будем использовать команды AT+CMGF и AT+CMGS чтобы передавать сообщения.

Работа схемы

Схема соединений устройства на макетной плате приведена на следующем рисунке.

Подключение GSM модуля к микроконтроллеру AVR ATmega16: схема соединений

В схеме необходимо сделать следующие соединения:
1. Tx и Rx GSM модуля to Rx (Pin14) и Tx (Pin15) микроконтроллера Atmega16 соответственно.
2. Кнопки to PD5 (Pin19) and PD6 (Pin20).
3. Соединения с ЖК дисплеем:
• RS — PA 0
• R/W — PA1
• EN — PA2
• D4 — PA4
• D5 — PA5
• D6 — PA6
• D7 — PA7

Создание проекта для Atmega16 в программной среде CodeVision

Необходимо выполнить следующую последовательность действий.

Шаг 1. Откройте CodeVision, выберите в ней пункт меню File -> New -> Project. В появившемся диалоговом окне нажмите Yes.

Создание нового проекта в CodeVision

Шаг 2. Откроется CodeWizard. Кликните в ней на первой опции, то есть AT90, затем нажмите OK.

Выбор первой опции в CodeVision

Шаг 3. Выберите свой микроконтроллер, в нашем случае им будет Atmega16L.

Выбор типа микроконтроллера в CodeVision

Шаг 4. Кликните на USART. Выберите передатчик и приемник кликнув по ним как показано на рисунке.

Выбор параметров USART в CodeVision

Шаг 5: Кликните на «Alphanumeric LCD» и выберите «Enable Alphanumeric LCD support» как показано на рисунке.

Выбор параметров ЖК дисплея в CodeVision

Шаг 6: Выберите пункт меню Program -> Generate, Save and Exit. На этом этапе можно сказать, что половина работы уже выполнена. Но если кто не хочет использовать CodeVision то, разумеется, всю эту часть кода можно запрограммировать и вручную.

Сохранение проекта в CodeVision

Шаг 7. Создайте новую папку на рабочем столе чтобы записывать туда наши файлы.

Создание новой папки на рабочем столе

У нас будет 3 диалоговых окна (будут появляться последовательно одно за другим) для сохранения наших файлов.

Сделайте то же самое (что и на представленном рисунке) с двумя другими диалоговыми окнами – то есть сохраните предлагаемые ими файлы.

После этого рабочая область программы будет выглядеть следующим образом:

Рабочая область программы в CodeVision

Теперь мы должны написать только часть кода, отвечающую за взаимодействие с модулем GSM.

Исходный код программы на языке С (Си) с пояснениями

В рассматриваемом нами способе создания программы все заголовочные файлы должны автоматически прикрепиться к проекту за исключением того что необходимо будет вручную подключить заголовочный файл delay.h и объявить все переменные. Полный текст программы будет приведен в конце статьи, здесь же будет дано пояснение лишь отдельных фрагментов программы.

#include <io.h>

// Alphanumeric LCD functions

#include <alcd.h>

#include <delay.h>

// стандартные функции ввода/вывода

#include <stdio.h>

unsigned char received_value(void);

unsigned char received_data,a,b,c;

unsigned int z;

unsigned char msg[15];

unsigned char cmd_1[]={«AT»};

unsigned char cmd_2[]={«AT+CMGF=1»};

unsigned char cmd_3[]={«AT+CMGS=»};

unsigned char cmd_4[]={«Call me»};

unsigned char cmd_5[]={«Receiver mobile number»};

Запрограммируем функцию, которая будет принимать данные из регистра UDR. Эта функция будет возвращать принятые данные.

unsigned char received_value(void)

{

while(!(UCSRA&(1<<RXC)));

{

received_data=UDR;

return received_data;

}

}

Используем цикл while в котором создадим два условных выражения, используя оператор if, одно для передачи сообщения, а другое – для приема. Кнопка передачи подсоединена к контакту PIND6 микроконтроллера, а кнопка приема – к контакту PIND5.

Когда кнопка передачи нажата (PIND6) будет выполняться первый оператор if и все команды, необходимые для передачи сообщения, будут выполняться последовательно.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

while(1){

//  lcd_clear();

      lcd_putsf(«Send->bttn 1»);

      lcd_gotoxy(0,1);

        lcd_putsf(«Receive->buttn 2»);

          if(PIND.6 == 1){  

          lcd_clear();

  lcd_gotoxy(0,0);

lcd_putsf(«Sending Msg…»);

for(z=0;cmd_1[z]!=»;z++)

{

UDR = cmd_1[z];

delay_ms(100);

}

UDR = (‘r’);

delay_ms(500);

for(z=0;cmd_2[z]!=»;z++)

{

UDR = cmd_2[z];

delay_ms(100);

}

Если кнопка приема нажата, в цикле while (b!=’+’) будет осуществляться проверка присутствует ли команда CMT или нет. Если присутствует, то будет выполняться последовательность команд начинающаяся со второй строчки цикла while, в результате выполнения этой серии команд на ЖК дисплее будет напечатано принятое сообщение.

   while(PIND.5 == 1){

      lcd_clear();

       lcd_gotoxy(0,0);  

   lcd_putsf(«Receiving Msg…»);

   b= received_value ();

while (b!=‘+’)         {

b= received_value ();

}

b= received_value ();

if(b==‘C’)

{

b= received_value ();

Следующий цикл предназначен для сохранения сообщения в массиве.

while (b!=0x0a)

{

b= received_value ();

}

for(b=0;b<3;b++)   {

             c=received_value();

             msg[b]=c;

}

Следующий цикл for служит для отображения сообщения на ЖК дисплее.

for(z=0;z<3;z++)

{

a=msg[z];

lcd_putchar(a); // PRINT IN lcd

delay_ms(10);

}

Компоновка проекта

Наш код закончен. Теперь нам необходимо скомпоновать (Build) наш проект. Для этого нажмите на кнопке Build как показано на рисунке.

Компоновка проекта в CodeVision

После компоновки проекта соответствующий HEX файл будет помещен в папку Debug-> Exe, которую можно найти в папке, которую вы создавали ранее для хранения проекта. Мы будем загружать этот HEX файл в микроконтроллер Atmega16 используя программу Sinaprog (можно использовать любую другую аналогичную программу, с которой вы привыкли работать).

Загрузка программы в Atmega16 с использованием Sinaprog

Подсоедините один конец FRC кабеля к программатору USBASP, а другой конец к контактам SPI микроконтроллера.

Распиновка FRC кабеля

Необходимо сделать следующие соединения:
1. Pin1 of FRC female connector -> Pin 6, MOSI of Atmega16
2. Pin 2 connected to Vcc of atmega16 i.e. Pin 10
3. Pin 5 connected to Reset of atmega16 i.e. Pin 9
4. Pin 7 connected to SCK of atmega16 i.e. Pin 8
5. Pin 9 connected to MISO of atmega16 i.e. Pin 7
6. Pin 8 connected to GND of atmega16 i.e. Pin 11

Мы будем загружать в микроконтроллер ранее сгенерированный Hex файл используя программу Sinaprog, поэтому мы должны открыть ее и выбрать в ней Atmega16 в выпадающем меню устройства (Device). Выберите HEX файл из папки Debug->Exe как показано на рисунке.

Загрузка программы в микроконтроллер с использованием SinaProg

Теперь кликните на Program и ваш код будет загружен в микроконтроллер ATmega16.

Ваш микроконтроллер запрограммирован. Теперь можете попробовать нажимать кнопки для передачи и приема сообщений от микроконтроллера к GSM модулю.

Полный код программы

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

#include <io.h>

// Alphanumeric LCD functions

#include <alcd.h>

#include <delay.h>

// стандартные функции ввода/вывода

#include <stdio.h>

unsigned char received_value(void);

unsigned char received_data,a,b,c;

unsigned int z;

unsigned char msg[15];

unsigned char cmd_1[]={«AT»};

unsigned char cmd_2[]={«AT+CMGF=1»};

unsigned char cmd_3[]={«AT+CMGS=»};

unsigned char cmd_4[]={«Call me»};

unsigned char cmd_5[]={«Receiver mobile number»};

void main(void)

{

// инициализация Port A

// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In

DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);

// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T

PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

// инициализация Port B

// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In

DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);

// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T

PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// инициализация Port C

// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In

DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);

// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T

PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

// инициализация Port D

// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In

DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);

// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T

PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

// инициализация USART (универсальный синхронно-асинхронный приемопередатчик)

// параметры связи: 8 бит данных, 1 стоповый бит, нет бита четности

// USART Receiver (приемник): On

// USART Transmitter (передатчик): On

// USART Mode (режим): Asynchronous

// USART Baud Rate (бодовая скорость): 9600

UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);

UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);

UCSRC=(1<<URSEL) | (0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);

UBRRH=0x00;

UBRRL=0x33;

lcd_init(16);

lcd_clear();

lcd_gotoxy(0,0);

lcd_putsf(«Welcome…»);

delay_ms(2000);

lcd_clear();

lcd_putsf(«Initialising GSM»);

delay_ms(4000);

lcd_clear();

while(1){

      lcd_putsf(«Send->bttn 1»);

      lcd_gotoxy(0,1);

        lcd_putsf(«Receive->buttn 2»);

          if(PIND.6 == 1){  

          lcd_clear();

  lcd_gotoxy(0,0);

lcd_putsf(«Sending Msg…»);

for(z=0;cmd_1[z]!=»;z++)

{

UDR = cmd_1[z];

delay_ms(100);

}

UDR = (‘r’);

delay_ms(500);

for(z=0;cmd_2[z]!=»;z++)

{

UDR = cmd_2[z];

delay_ms(100);

}

UDR = (‘r’);

delay_ms(500);

for(z=0;cmd_3[z]!=»;z++)

{

UDR = cmd_3[z];

delay_ms(100);

}

UDR = (‘»‘);

delay_ms(100);

for(z=0;cmd_5[z]!=»;z++)

{

UDR = cmd_5[z];

delay_ms(100);

}

UDR = (‘»‘);

delay_ms(100);

UDR = (‘r’);

delay_ms(500);

for(z=0;cmd_4[z]!=»;z++)

{

UDR = cmd_4[z];

delay_ms(100);

}

UDR = (26);                   // ctrlZ-> передать сообщение

delay_ms(500);

lcd_clear();

  lcd_gotoxy(0,0);

lcd_putsf(«Message Sent.»);

delay_ms(1000);

lcd_clear();

}

   while(PIND.5 == 1){

      lcd_clear();

       lcd_gotoxy(0,0);  

   lcd_putsf(«Receiving Msg…»);

   b= received_value ();

while (b!=‘+’)            // infinite loop when + equal to +. otherwise until the loop infinite

{

b= received_value ();

}

b= received_value ();

if(b==‘C’)

{

b= received_value ();

if(b==‘M’)

{

b= received_value ();

if(b==‘T’)

{

b= received_value ();

if(b==‘:’)

{

b= received_value ();

while (b!=0x0a)                          // waiting upto next line if no means till loop infinte

{

b= received_value ();

}

for(b=0;b<3;b++)   {

             c= received_value ();

             msg[b]=c;

}

    lcd_clear();

for(z=0;z<3;z++)

{

a=msg[z];

lcd_putchar(a);                                // PRINT IN lcd

delay_ms(10);

}

}

}

}

}

delay_ms(3000);

lcd_clear();  

}

}

}      

unsigned char received_value(void)

{

while(!(UCSRA&(1<<RXC)));

{

received_data=UDR;

return received_data;

}

}

Видео, демонстрирующее работу схемы

Загрузка…

3 848 просмотров

   Сегодня будем разбирать понятие прерывания и как его использовать. Естественно не обойдется без учебной программы, но на этот раз моргать светодиодами не будем. Хорош уже. Сделаем подобие дверного звонка.

Задача: заставить микроконтроллер по нажатию кнопки издавать звуковой сигнал.
Схема для нашего примера здесь. Файлы проекта здесь.

Создаем в старом workspace проект ring.
Задаем настройки проекта для конфигурации Release:

Выбираем тип микроконтроллера.
General Options > Target > Processor configuration
У меня это ATmega8535.  

Разрешаем использование имен битов определенных в хидер файле
В General Options > System ставим галочку Enable bit definitions in I/O-Include files
До сих пор мы не пользовались именами битов, но сегодня они нам понадобятся.   

Меняем тип выходного файла.
Linker > Output.
B поле Output file cтавим галочку Override default и заменяем расширение d90 на hex
В поле Format выбираем Other и в выпадающем меню Output format выбираем тип файла intel-standart

Сохраняем проект и workspace.

______________________________  Прерывание  ___________________________

    Представьте себе ситуацию. Вы сидите на работе и корпите над очередной микроконтроллерной програмулиной. Подходит к вам начальник и говорит: “Слушай, Паш, нам  осциллографы в отдел закупили — Tektronix, четырехканальные. Помоги Васе  притащить их”. Вы думаете: ”Ну, е-мое, только мысль поперла.. и на тебе”. А начальник так смотрит на вас, а глаза у него такие добрые, такие добрые. Как тут ему откажешь. Ну, вы все бросаете и идете с другом за осциллографами. Притащили. Отчитались. И снова сели за свою программу. Вот примерно так и выглядит механизм прерывания.

    Довольно просто, но есть ряд принципиальных моментов.
Во-первых:
—    вы делали свою работу
—    параллельно кто-то покупал осциллографы
—    по наступлению события «осциллографы закупили» — вы прерываете выполнение своей работы
—    некоторое время вы занимаетесь другой работой – тащите осциллографы
—    потом вы возвращаетесь на рабочее место и продолжаете делать свою работу с того места, на котором остановились

Во-вторых:
—    вы вполне могли бы послать начальника и никуда не идти
—    уйдя за осциллографами, вы могли задержаться там надолго, а то и вовсе не вернуться
—    вернувшись на рабочее место, вы могли бы уже позабыть свои гениальные идеи

    Все это очень похоже на то, что происходит в микроконтроллере. Микроконтроллеры AVR имеют в своем составе целую тучу периферийных устройств (таймеры/счетчики, аналого-цифровой преобразователь, аналоговый компаратор, асинхронный приемопередатчик…и т.д). Мощь микроконтроллера в том, что все эти устройства могут работать параллельно и независимо друг от друга, а также параллельно выполняемой программе. Каждое периферийное устройство может вызывать прерывание по наступлению определенного события. Прерывание будет происходить только в том случае, если оно разрешено. Разрешение прерываний устанавливается для каждого устройства отдельно. Помимо этого есть флаг глобального разрешения/запрещения всех прерываний – это I флаг в регистре SREG. При возникновении прерывания микроконтроллер сохраняет содержимое счетчика команд PC в стеке, то есть запоминает место, на котором его прервали.  Загружает в счетчик команд адрес соответствующего вектора прерывания и переходит на этот адрес. Попадает на команду безусловного перехода по которой переходит на подпрограмму обработки прерывания. Запрещает прерывания сбросом флага I, выполняет подпрограмму. Выполнив подпрограмму обработки прерывания, микроконтроллер разрешает прерывания, устанавливая флаг I, и восстанавливает содержимое счетчика команд, то есть возвращается на то же место программы, на котором его прервали.

    По идее, обработчик прерывания не должен повреждать содержимое регистров микроконтроллера, потому что они могут содержать данные программы выполняемой в тот момент. Для этого в начале подпрограммы обработки прерывания содержимое регистров микроконтроллера сохраняют в стеке, а в конце подпрограммы восстанавливают. Таким образом, выйдя из прерывания, микроконтроллер сможет продолжить выполнение программы, как ни в чем не бывало. Программируя на ассемблере, сохранение регистров прописывает сам программист, на Си – это делает компилятор.

_______________________________________________________________

   Теперь поговорим о таймере. ATmega8535 имеет на борту три  таймера/счетчика — два восьмиразрядных (T0, T2) и один шестнадцатиразрядный (T1). Мы будем использовать восьмиразрядный таймер/счетчик T0. В состав этого таймера входят три регистра — регистр управления TCCR0, счетный регистр TCNT0 и регистр сравнения OCR0. Когда таймер запущен, счетный регистр TCNT0 увеличивает свое значение на единицу на каждый перепад тактового сигнала. Частота тактового сигнала выбирается из нескольких возможных значений в регистре управления TCCR0. Также с помощью этого регистра устанавливается режим работы таймера. Таймер T0 может вызвать прерывание по наступлению события “переполнение” – это когда переполняется счетный регистр TCNT0 и по наступлению события “совпадение” – это когда значение счетного регистра TCNT0 становится равным значению регистра сравнения OCR0. Флаги разрешающие эти прерывания находятся в регистре TIMSK. 
    Мы настроим таймер/счетчик Т0 так, чтобы он вызывал прерывание по событию “совпадение” с частотой 5 кГц. В функции обработчике будем инвертировать состояние вывода микроконтроллера, к которому подключен пьезодинамик. Таким образом, частота пищания пьезика будет равна 2,5 кГц.  (Подключен именно пьезодинамик! Не перепутайте. У пьезодинамика сопротивление зависит от частоты и на 2,5 КГц оно обычно еденицы Ком, поэтому его можно подключать к выводу микроконтроллера напрямую, без ограничительного резистора).

    Теперь о программе. Построчно писать программу уже не получится, поэтому я сразу приведу ее текст. Ниже мы последовательно разберем все ее строки, и все станет понятно. Макросы я намеренно не стал использовать, программа маленькая, не хочется ее загромождать.

//Подаем голос микроконтроллером AVR
#include <ioavr.h>
#include <intrinsics.h>

int main(void)
{
//настраиваем порты ввода-вывода
  DDRD = (0<<PD1)|(1<<P0);
  PORTD = (1<<PD1)|(0<<PD);

//настраиваем таймер Т0
  TCCR0 = (1<<WGM01)|(0<<GM00)|(0<<CS02)(1<<CS01)(0<<CS00)
  TCNT0 = 0;
  OCR0 = 0xc8;

  //разрешаем прерывания  
  __enable_interrupt();

  //основной цикл программы – опрос кнопки
  while(1){
       if ((PIND & (1<<PD0)) == 0)
            TIMSK = (1<<OCIE0);
       else
            TIMSK = 0;
  }
  return 0;
}

//обработчик прерывания таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
        PORTD ^= (1<<PD1); //инвертируем сигнал на выводе PD1
}

Настройка портов

    В нашей схеме к порту D подключена кнопка и пьезодинамик. Вывод, к которому подключена кнопка, нужно настроить на вход и включить подтягивающий резистор. Вывод, к которому подключен пьезодинамик, нужно настроить на выход.

    DDRD = (0<<PD1)|(1<<PD0);
    PORTD = (1<<PD1)|(0<<PD0);

Настройка таймера

        Режим работы таймера Т0 – СТС(сброс при совпадении), тактовый сигнал – clk/8. Отражаем это в регистре TCCR0

    TCCR0 = (1<<WGM01)|(0<<WGM0)|(0<<CS02)(1<<CS01)(0<<CS00)

Обнуляем на всякий случай счетный регистр TCNT0

    TCNT0 = 0;

В регистр сравнения OCR0 записываем 0xc8. Почему? Потому что я посчитал это на калькуляторе. Ну а на бумаге этот расчет выглядит так.
Тактовая частота микроконтроллера 8 МГц
Тактовый сигнал таймера равен 8000000 Гц/8 = 1000000 Гц.    
Время одного такта таймера 1/1000000 = 1 мкс
Время одного такта нужной нам частоты 1/5000 Гц = 200 мкс
Сколько тактов таймера укладывается в 200  мкс?   200/1 = 200 тактов
200 в шестнадцатеричной системе = 0xс8

    OCR0 = 0xс8;

Подробное описание таймера T0 смотрите в документации на ATMega8535.

Таймер мы настроили, разрешаем общее прерывание, используя встроенную функцию.

    __enable_interrupt();

Опрос кнопки

    Когда кнопка не нажата, вывод микроконтроллера через внутренний подтягивающий резистор подключен к питанию, то есть на выводе присутствует  единичка, когда кнопка нажата, вывод замкнут на землю, то есть на выводе ноль. Чтобы определить нажата ли кнопка, нужно считать содержимое регистра PIND и проверить значение нулевого бита (к PD0 подключена кнопка). Опрашивать кнопку будем в бесконечном цикле.

 

while(1)
  {
        if ((PIND & (1<<PD0)) == 0){
                        //если кнопка нажата – микроконтроллер должен верещать
       }
       else {
                         //если нет — молчать как рыба
       }
  }

Не забывайте == это не оператор присваивания =.

Обработка нажатия/отпускания кнопки

    По нажатию кнопки мы будем разрешать прерывание таймера T0, по отпусканию  — запрещать. Для этого будем манипулировать битом OCIE0 регистра TIMSK

TIMSK = (1<<OCIE1); // разрешаем прерывание таймера Т0 по событию совпадение

TIMSK = 0; //запрещаем прерывание

Поскольку мы используем всего один таймер, то нет нужды в установке или сбросе отдельных битов.

Функция прерывания

Это не совсем простая функция, поскольку ее вызывает микроконтроллер, и она имеет особенный синтаксис.

_____________________ Cинтаксис функции прерывания _____________________

Функция прерывания задается с помощью директивы #pragma vector= и служебного слова __interrupt. Функция должна иметь тип void и не должна принимать никаких параметров.

#pragma vector = Address
__interrupt void Name(void)
{
    //здесь располагается наш код
}

Name – имя функции, выбираем на наше усмотрение
Address – адрес вектора прерывания, можно задавать числом, можно именами определенными в заголовочном файле микроконтроллера (iom8535.h – раздел Interrupt Vector Definitions)

______________________________________________________________

Для нашей задачи функция-обработчик прерывания выглядит так

#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
        PORTD ^= (1<<PD1); //инвертируем сигнал на выводе PD1
}

Ну вот собственно и все. Надеюсь все понятно.
В следующий статье заставим микроконтроллер играть мелодию.

Схема для нашего примера здесь. Файлы проекта здесь.

Достаточно часто в личке ко мне обращаются люди с просьбой дать ссылки на полезные сайты, нужную информацию по программированию микроконтроллеров, необходимые программы и т.п. находясь при этом в самом начале своего познания микроконтроллеров. Сам я проходил через это буквально полтора года назад, имея нулевые знания и знаю, насколько это сложно, дать себе первоначального пинка, разобраться в лавине информации по микроконтроллерам, которую выдают поисковики, когда на тебя обрушивается куча непонятной информации и т. п.

Постараюсь объяснить на простом языке, для людей, умеющих держать паяльник, знающих, что такое цифровая микросхема логики, умеющих читать схемы и пользоваться мультиметром.

Микроконтроллеры бывают разных фирм, которые делают одно и тоже дело, но разными методами. Сравнить это можно с человеческими расами: европейцы, китайцы и африканцы например. Я лично работаю с микроконтроллерами фирмы Атмел, про них и буду говорить. Ну уж пошло сравнение с расами, пускай это будут европейцы.) Программы для микроконтроллеров пишут на языках программирования. Я рекомендую начать с языка Си. Это древний и простой язык. Для написания текста програмы используют программы компиляторы. Они позволяют создавать, редактировать и переваривать написанный программистом текст программы в код (прошивку), который можно загрузить (прошить) в микроконтроллер. Таких программ есть множество. Пример для Атмел: Code VisionAVR, родная от Атмел AVR Studio, Bascom-avr и ещё.
Эти программы делают одно и тоже дело, но своими методами, особенностями достоинствами и недостатками. При это текст Си в тих программах компиляторах немного отличается, но в общем похож. Можно сравнить с различием украинского, русского и белорусского языка. Я использую Code VisionAVR, что и советую начинающим.

Далее я приведу простой текст программы, написанный на языке Си в компиляторе Code VisionAVR для микроконтроллера ATTiny13A. В конце темы есть проект, прошивка и проект для эмулятора протеуса. Микроконтроллер в этой программе умеет делать простую вещь: при помощи кнопки менять логическое состояние на двух выходах, при этом короткое нажатие меняет состояние первого выхода а длинное — второго. В автомобиле например эту схему можно применить для управления одной кнопкой обогревом заднего стекла (которая есть у многих штатно) и добавленным обогревом зеркал. Нажал коротко на кнопку — сработал обогрев стекла, нажал ещё — обогрев стекла выключился. Если нажать и удерживать кнопку, то через какое-то время включиться обогрев зеркал. Если нажать и удерживать кнопку повторно — обогрев зеркал отключится.

Для понятия текста нужно знать грамматику, правила писанины языка Си, этого материала в интернете предостаточно. Так же желательно ознакомиться хотя бы с материалом, по использованию мастера создания проектов в CodeVisionAVR.

Текст программы:

/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
www.hpinfotech.com

Project :
Version :
Date : 28.01.2012
Author :
Company :
Comments:

Chip type : ATtiny13A
AVR Core Clock frequency: 9,600000 MHz
Memory model : Tiny
External RAM size : 0
Data Stack size : 16
*****************************************************/

#include <tiny13a.h>
#include <delay.h>

unsigned char b, trig;

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

PORTB=0x01;
DDRB=0x06;

TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

GIMSK=0x00;
MCUCR=0x00;

TIMSK0=0x00;

ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;

ADCSRA=0x00;

while (1)
{
if (PINB.0==0)
{
if (trig==0) b++;
if (b>100)
{
if (PINB.2==0)PORTB.2=1;
else PORTB.2=0;
trig=1;
b=0;
}
}
else
{
if (b>4)
{
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;
b=0;
}
b=0;
trig=0;
}

delay_ms(10);

}
}

А теперь поподробнее.

/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
www.hpinfotech.com

Project :
Version :
Date : 28.01.2012
Author :
Company :
Comments:

Chip type : ATtiny13A
AVR Core Clock frequency: 9,600000 MHz
Memory model : Tiny
External RAM size : 0
Data Stack size : 16
*****************************************************/

Это шапка, в которой содержится описание проекта, необходимые данные. Текст закомментирован знаками комментария /* в начале и */ в конце. Все, что находится между этими знаками программой не выполняется. Самое полезное здесь это указание типа микроконтроллера и его частота.

#include <tiny13a.h>
#include <delay.h>

Это ссылка на библиотеку. Если какая либо библиотека необходима, то она должна быть здесь указана. У нас есть библиотека самого микроконтроллера tiny13a.h, и библиотека задержек времени.

unsigned char a, b, trig;

Объявление трех переменных. unsigned char . Что это такое можно посмотреть здесь Вообще всё непонятное копируем в буфер и ищем в поисковике.

void main(void)
{
// Declare your local variables here

void main(void) — это оператор, говорящий что началась основная часть программы на Cи и микроконтроллер будет её с этого места выполнять. Все что начинается с // — это комментарий. Старайтесь чаще ими пользоваться. Вообще конкретный комментарий генерирует сам компилятор, как и во многих других местах. Большинство комментариев я удалил, что уменьшить текст.

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

В комментарии по английски написано, что это такое. Это первая команда микроконтроллеру, одна из команд, которая настраивает нужные функции, порты и необходимые части микроконтроллера, необходимые для его работы и запуска.
Конкретно это настройка частоты делителя тактовой частоты микроконтроллера. Теперь подробнее:

Микроконтроллер имеет тактовый генератор, который задается в мастере и который потом можно изменить в свойствах проекта если что. У нас эта частота 9.6 мегагерца, как видно в шапке.

При прошивке микроконтроллера эту же частоту нужно указать во фьюзах.
CLKPR=0x80; и CLKPR=0x00; это команды настройки регистра внутреннего делителя этой частоты. Задается оно в мастере в первом окне «CHIP». Если у нас выбран делитель 1, то тактовая частота делиться на 1, то есть остается без изменений. Если указать например делитель 128, то соответственно тактовая частота делиться на это число. 9.6Мгц / 128 = 75кГц. и значения регистра делителя будет выглядеть:
CLKPR=0x80;
CLKPR=0x07;

Особо внимательные заметили, в регистр делителя CLKPR сначала пишется число 0x80 а затем сразу 0x00. Нафига пишется сначала одно значение а потом сразу другое? Если у вас возникают какие либо вопросы по регистрам и не только, приучайтесь сразу читать даташиты. Там все подробные ответы на чистом английском языке. Открываете даташит, вставляете в поисковик текста название регистра (CLKPR ) и ищете его описание, за что какие биты данного регистра отвечают. Конкретно у этого регистра для изменения делителя необходимо записать единичку в седьмой бит, после чего микроконтроллер даст изменить и выбрать необходимый делитель в первых четырех битах этого регистра. После того, как пройдет четыре такта выполнения команд процессора, изменить регистр будет уже нельзя. Нужно снова сначала изменить седьмой бит CLKPR=0x80 а затем указать делитель CLKPR=нужный делитель

PORTB=0x01;
DDRB=0x06;

Команды управления и настройкой портов микроконтроллеров — ножек чипа. Задается тоже в мастере. В этих регистрах задается работа на вход порта PB0 и подключается к нему внутренний Pull-up резистор. Порты PB1 и PB2 настраиваются «на выход» с логическим нулем на выходе в их состоянии.

В колонке DataDitection мы указывает тип порта: вход или выход (in или out)
В колонке PullUp/Output Value указываем подключение подтягивающего резистора pullup если порт настроен на вход (P — подключен, Т — неподключен) Если порт настроен на выход, то можно указать его логическое состояние 0 или 1. У нас нули. Строчки Bit0 — Bit5 это порты микроконтроллера PORTB0 — PORTB5

Если посмотреть сгенерированный компилятором комментарий, то можно увидеть соответствие пинов и их настройку:
// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=In
// State5=T State4=T State3=T State2=0 State1=0 State0=P

Если перевести из 16-тиричного в двоичный значение регистров, то можно понять даже без даташита назначение битов в регистре:

PORTB=0x01 PORTB=0b00000001
DDRB=0x06 DDRB=0b00000110

Напоминаю, что при разложении в двоичный код младшие значения справа а старшие слева.
Незначащие нули слева можно не писать:

PORTB=0b1;
DDRB=0b110;

А можно вообще написать в десятичной системе:
PORTB=1;
DDRB=6;

Далее по тексту кода идет:

TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
GIMSK=0x00;
MCUCR=0x00;
TIMSK0=0x00;
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;
ADCSRA=0x00;

Настройка таймера микроконтроллера, прерываний, АЦП, компаратора и всего такого пока сложного. Пока его не используем — рановато. У всех этих регистров стоят в значениях нули, это значит, что они отключены. А особо внимательные заметили, что какой-то регистр ACSR имеет значение =0x80; Лезем в даташит и читаем:

Analog Comparator Control and Status Register – ACSR

Вообще, как правило название всех регистров это сокращение от первых букв или части их полного названия.

Если стоит значение данного регистра 0x80, значит в двоичной системе это число 10000000, значит стоит единичка в 7 бите этого регистра, значит читаем в даташите, что он означает:

• Bit 7 – ACD: Analog Comparator Disable
When this bit is written logic one, the power to the Analog Comparator is switched off.
This bit can be set at any time to turn off the Analog Comparator. This will reduce power
consumption in Active and Idle mode. When changing the ACD bit, the Analog Comparator
Interrupt must be disabled by clearing the ACIE bit in ACSR. Otherwise an interrupt
can occur when the bit is changed.

По-русски это означает, что установка единицы в этом бите отключает аналоговый компаратор, что его можно выключить в любой момент, что это приводит к снижению потребления электричества, и в конце текста написано про зависимости и что нужно соблюдать, если нужно изменять этот бит.

while (1)

После того, как микроконтроллер настроен запущен и выполнена инициализация необходимых частей и выполнены необходимые первоначальные команды в void main(void) в дело вступает его величество главный цикл. Все что находиться внутри этого главного цикла while (1) и заключено в скобки начала { и конца } будет крутиться, команды выполняться по кругу от начал до конца. А у нас в нашем коде будет крутиться алгоритм опроса кнопки, подключенной к порту PB0, от состояния которой (нажата кнопка или нет) будет меняться состояние выходных портов PB1 и PB2

На картинке видна схема собранную в эмуляторе Протеус схему, которая позволяет видеть работу кода программы.

Теперь про сами основные команды, которые находятся внутри цикла. Все команды используют один оператор if Это условие ЕСЛИ.

if (PINB.0==0)
{

кучка кода;
}
else
{

ещё кучка кода;
}

Подробнее:

if (PINB.0==0)

Если в регистре PINB в бите, отвечающем за порт PB0 микроконтроллера.0 содержится значение равное нулю ==0, то выполняем кучку кода, которая находится далее в границах скобок { и }
Короче, если нажата кнопка то выполняется следующий код в границах последующих скобок { и }
Далее после кучки кода в скобках видим оператор else и ещё кучку кода за ним в скобках { и }

Оператор else переводится не как ещё а как иначе

Оператор if и else всегда работают в паре, сначала идет if затем else. Оператор else можно не использовать совсем, если он не нужен.

В нашей ситуации алгоритм можно описать так:

если (нажата кнопка подключенная к порту PB0)
{

то выполняем кучку кода;
}
иначе
(кнопка не нажата)
{
выполняем эту кучку кода;
}

Так как это все находится внутри главного цикла, то этот код будет выполняться по кругу, будет постоянно опрашиваться кнопка и будет выполняться нужная кучка кода

Теперь рассмотрим кучку кода, которая выполняется, если кнопка нажата:

if (trig==0) b++;
if (b>100)
{
if (PINB.2==0)PORTB.2=1;
else PORTB.2=0;
trig=1;
b=0;
}

Операторы можно вкладывать друг в друга, как матрешку. то есть выполняется одно условие, потом если условие сработало, то другое внутри первого условия и т.д.

if (trig==0) b++;

Если переменное значение trig равняется нулю, то выполняем инкремент переменной b Инкремент — операция увеличения значения, хранящегося в переменной, на 1. То есть при проходе выполнения кода, если процессор натыкается на команду инкремента b++, то процессор прибавляет единичку в число, которое находится в переменной b
Так же здесь применяется упрощенная «орфография» написания условия и команды, без скобок { и }:

if (trig==0) b++;
это же самое что:
if (trig==0)
{
b++;
}

Такое представление используют, если после условия всего одна команда.

Немного отвлеклись, возвращаемся:

if (trig==0) b++; — если значение переменной равно нулю (а оно у нас равно нулю) то выполняем инкремент переменной b — переменная в была равна нулю, теперь стало единице.

Следующая операция:

if (b>100)
{

кучка кода;
}

Если переменная b больше ста, то выполняем кучку кода внутри скобок.

Переменная b за каждый круг цикла прибавляется на единичку и в итоге через сто «кругов» главного цикла выполниться условие, которая находится далее внутри скобок { и }

Теперь рассмотрим что же там делается, если нажата кнопка, если прошло сто кругов цикла:

if (PINB.2==0)PORTB.2=1;
else PORTB.2=0;
trig=1;
b=0;

Здесь мы видим ещё одно условие (жирная такая матрешка получилась))

if (PINB.2==0)PORTB.2=1;
Если регистр состояния выходного порта PB, а точнее PB2 равен нулю, то меняем его состояние на единичку PORTB.2=1.
else PORTB.2=0;
Иначе пишем в регистр нолик. Или если по-другому: если регистр состояния выходного порта PB2 равен единице, то меняем его на ноль.

Короче если происходит выполнение этих условий и команд, то меняется логическое состояние выхода 2 (PB2) на схеме.

Если полностью описать: если нажата кнопка, если прошло сто кругов главного цикла, то меняем логическое состояние выхода 2 — PORTB.2 в коде он же порт PB2 на схеме.

Как уже стало понятно этот кусок кода отрабатывает длительное нажатие кнопки.
Но этого мало, дальше ещё есть две выполняемые команды присвоения:

trig=1;
b=0;

trig=1; присвоение единице этой переменной необходимо, что бы описанное выше условие работы инкремента b++ перестало работать
b=0; обнуляем переменную b.

В итоге при длительном нажатии кнопки, условие при котором меняется состояние порта PB2 выполняется единожды, до тех пор, пока кнопка не будет отжата кнопка, ибо инкремент не будет работать и условие if (b>100) больше не сработает, если тупо нажать кнопку и не отпускать совсем.

Теперь вторая часть кучки кода, которая следует за первым условием:
else
{
if (b>4)
{
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;
b=0;
}
b=0;
trig=0;
}

Если кнопка отжата:
Опишем её с конца:

trig=0; присваиваем переменной trig значение ноль. Необходимо, что бы после длительного нажатия, когда наступит последующее отжатие кнопки микроконтроллер снова был готов к нажатиям кнопки ( срабатывало условие инкремента if (trig==0) b++;)

b=0; При не нажатой кнопке значение переменной b равняется нулю.

if (b>4)
{
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;
b=0;
}

Подробнее:
if (b>4)
Если значение переменной b больше четырех, то выполняем следующий код:
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;

Если состояние порта BP1 равно нулю, то делаем единицу, если нет, то ноль.

Это условие и команда отрабатывает кроткое нажатие кнопки. Если нажата кнопка, то начинает работать инкремент b++; значение которого начинает увеличиваться. Если отжать кнопку и при этом значение переменной b будет больше четырех ( но меньше ста — а то сработает длинное нажатие) то состояние выходного порта PB1 (он же выход 1 на схеме, он же PORTB.1 в коде) поменяется, сработает алгоритм короткого нажатия кнопки.

Если значение переменной b при отжатии меньше четырех, то условие не срабатывает и ничего не происходит. необходимо для работы «дребезга контактов» и ложных срабатываний.

И последнее это присвоение переменной b нулевого значения, что бы обработка алгоритма короткого нажатия происходило единожды.

В оконцовке главного цикла виднеется команда:

delay_ms(10);

Это задержка в главном цикле. То есть, выполняется пошагово команды, затем процессор натыкается на команду delay_ms(10); и начинает её выполнять. В итоге процессор будет 10 миллисекунд ждать и ничего не делать в этой строчке, затем опять приступит к выполнению команд.
Находясь в одном общем цикле, скорость нарастания значения инкремента b++ зависит от времени задержки, указанной в delay_ms.

Команда delay_ms находится в библиотеке задержек #include <delay.h>, которую мы для этого и включили в начале кода.

Как видно из описания, длинное нажатие срабатывает от фронта сигнала нажатия кнопки ( начинает работать инкремент) а короткое нажатие кнопки — по спаду, то есть срабатывает по отжатию кнопки.

Вообще выполняемая здесь последовательность: условие + инкремент достаточно часто используемая команда и в языке Си присутствует отдельный оператор для этого for

Архив с прошивкой, исходником и моделью Протеуса:
umat.ru/files/Button_13.zip
ВНИМАНИЕ!
Архив перезалил 22 сентября 2014 года, обнаружил косяк в выставленной частоте в проекте. Теперь тактовая частота 1.2 Мегагерца, при этом фьюзы стоят по дефолту и их при прошивке трогать вообще не надо

Пример реализации схемы rusgg
www.drive2.ru/cars/gaz/ga…usgg/journal/570874/#post

Область применения микроконтроллеров безгранична. Их используют в любых электронных устройствах для осуществления контроля. Кроме того, они находятся во всех бытовых приборах – микроволновках, электрочайниках, утюгах, стиральных машинах — микроконтроллер можно запрограммировать под любую функцию.

Содержание

  1. История появления
  2. Что такое микроконтроллер
  3. Принцип работы микроконтроллера
  4. Назначение и область применения микроконтроллера
  5. Питание микроконтроллера
  6. Подключение
  7. Управление микроконтроллером
  8. Тактирование микроконтроллеров
  9. Семейства микроконтроллеров
  10. Типы корпусов микроконтроллеров
  11. В чем отличие микроконтроллера от микропроцессора?
  12. Устройства на микроконтроллерах
  13. Что нужно для программирования микроконтроллера
  14. Языки программирования
  15. Среда разработки
  16. Основы программирования
  17. Советы начинающим программистам микроконтроллеров

История появления

Работы над изобретением микропроцессора велись с начала 1970-х годов. Первой компанией, разработавшей его, была компания Intel. Уже в 1971 году ее был выпущен первый микроконтроллер 4004, который состоял из 2300 полупроводниковых транзисторов, а по размеру был не больше ладони. Это стало возможным, после того как для микросхемы был специально разработан кристалл процессора.

Первый микроконтроллер 4004

Несмотря на маленькие размеры, производительность микропроцессора не уступала компьютеру Eniac, имеющему габариты в 85 м3. Особенностью этого устройства было то, что оно могло обрабатывать только 4 бита информации.

В ближайшие полгода еще несколько компаний заявили о создании аналогичных изделий.

К концу 1973 года Intel выпускает 8-зарядный микропроцессор. Он был настолько удачно разработан, что и сегодня считается классикой.

Через несколько месяцев фирма Motorola выпускает свой 8-битовый микропроцессор 6800. Он стал сильным конкурентом интеловской микросхеме, т. к. имел более значительную систему прерываний и одно напряжение электропитания. В 8080 их было три.

Внутренняя архитектура 6800 тоже отличалась. В ней не было регистров общего назначения, в которых могли сохраняться как адресная информация, так и числовые показатели. Вместо них, в процессоре появился еще один полноценный аккумулятор для обработки данных и 16-разрядные регистры для хранения адресов. Работа с памятью у 6800 выполнялась быстрее и была проще, но 8080 тратил меньше времени на обмен внутренней информацией между регистрами.

Оба эти изделия имели как положительные стороны, так и недоработки. Они стали родоначальниками двух больших семейств микропроцессоров – Интел и Моторола, которые конкурируют между собой до сих пор.

В 1978 году Интел выпустила 16-разрядный микропроцессор, который IBM использовала для разработки персональных компьютеров. Моторола не отстала от своего конкурента и тоже выпустила 16-разрядный микропроцессор, который использовали Atari и Apple.

Сейчас существует более 200 разновидностей микроконтроллеров. Количество компаний, их изготавливающих, перевалило за два десятка. Широкое распространение у разработчиков получили:

  • 8-битные микроконтроллеры Pic компании Microchip Technology и AVR от Atmel;
  • 16-битовые MSP 430 фирмы TI;
  • 32-битные ARM от одноименной компании.

В России пользуются популярностью микроконтроллеры Renesas Electronics, Freescale, Samsung.

Что такое микроконтроллер

Микроконтроллер по сути является микросхемой, который состоит из:

  • Центрального процессора. В него входят блок управления, регистры, ПЗУ (постоянное запоминающее устройство).
  • Периферии, которая включает порты ввода-вывода, контроллеры прерываний, таймеры, генераторы различных импульсов, аналоговые преобразователи и подобные элементы.

Зачастую микроконтроллер называют микропроцессором. Но это не совсем так. Последний осуществляет только определенные математические и логические операции. А в состав микроконтроллера входит и микропроцессор с другими элементами, являясь лишь частью МК.

Принцип работы микроконтроллера

Несмотря на сложное устройство принцип работы микроконтроллера очень прост. Он основан на аналоговом принципе действия. Система понимает лишь две команды («есть сигнал», «нет сигнала»). Из этих сигналов в его память вписывается код определенной команды. Когда МК считывает команду, он ее выполняет.

В каждом из МК прописаны свои базовые наборы команд. И только их он способен принимать и выполнять. Сочетая отдельные команды между собой, можно написать уникальную программу, по которой будет работать любое электронное устройство именно так, как требуется.

Микроконтроллер Atmel

В зависимости от содержащихся в МК набора программ, они делятся на:

CISC – комплекс большого числа базовых команд;

RISC – только необходимые команды.

Большинство контроллеров содержит RISC набор. Объясняется это тем, что такой МК проще изготовить, он дешевле и больше пользуется спросом у разработчиков электронной техники.

Назначение и область применения микроконтроллера

Благодаря тому, что микроконтроллеры AVR очень просты в использовании, обладают высокой способностью интегрирования и низкой потребляемой мощностью, области их применения разнообразны:

  • автомобилестроение;
  • робототехника;
  • самолето- и судостроение;
  • промышленное оборудование;
  • электронные детские игрушки;
  • компьютеры, телефоны;
  • электронные музыкальные инструменты;
  • бытовая техника;
  • медоборудование;
  • управление шлагбаумами и воротами;
  • светофоры, семафоры;
  • железнодорожный транспорт.

Это не полный перечень областей применения МК.

Основное назначение МК – контролировать все процессы, которые происходят на его платформе. От включения или выключения света по хлопку до поднятия штор при изменении освещенности на улице. По сути, МК осуществляет контроль за состоянием неких переменных и изменение системы в динамических условиях.

Питание микроконтроллера

Для работы микроконтроллеру, как и любому электронному устройству, необходима энергия. Напряжение МК Atmel AVR находится в диапазоне 1.8–5.5 Вольт и зависит от модели и серии. Большинство приборов работает от 5 Вольт. Но встречаются и низкочастотные модели (Attiny 2313), нижняя граница у которых от 1,8 В.

Кроме того, на работу МК влияет и частота поступающего тока. Низкое напряжение требует и низких пределов частот. Чем выше частота, тем быстрее работают определенные модели.

Так, чтобы обеспечить работу контроллеров серии AVR, на все плюсовые входы нужно подавать 5 В, а нулевой заземляют.

Если у модели несколько вводов и выводов питания, то подключать их нужно все.

На аналогово-цифровой преобразователь питание подают через дополнительные фильтры. Это поможет избавиться от помех, которые могут изменять показания напряжения. При этом на плюсовой ввод подается напряжение через фильтрующий дроссель. А нулевые выводы разделяют на цифровые и аналоговые. Причем соединяться они могут только в одной точке.

Кроме того, необходимо установить и конденсаторы, лучше керамические, из расчета 1 на 100 нанофарад.

Подключение

Через микроконтроллер можно подключить к локальной сети любой девайс. В качестве таковой можно рассмотреть Ethernet. Прежде всего, определимся с понятиями.

Ethernet – это набор стандартов IEEE 802.3, которые описывают разнообразные технологии локальных сетей: общий канальный уровень и набор технологий физического уровня, включающий в себя для передачи информации оптоволокно, витую пару, коаксиал с различными скоростями.

Подключение Ethernet к микроконтроллеру

Понять, как работает локальная сеть, можно через модель OSI. Она включает в себя несколько уровней:

  1. Физический. Состоит из витой пары, драйверов и трансформаторов, по которым происходит передача данных.
  2. Канальный. Через него передаются Ethernet-фреймы между узлами локальной сети.
  3. Сетевой. По нему происходит передача пакетов. Они могут передаваться через несколько сетей, различающихся по технологиям физического и канального уровней.
  4. Транспортный. Связывает узлы между собой. Перед отправкой данных транспортный уровень представляет их в виде пакета сетевого уровня и передает другому узлу. Он может отправлять и группы пакетов одновременно. Если используется протокол с установкой соединения, то перед отправкой транспортный уровень устанавливает соединение, контролирует его качество, а только потом передает пакет данных.
  5. Прикладной. Решает прикладные задачи, те, ради которых создавался. С внешним миром он обменивается данными по стандартному или эксклюзивному протоколу.

Каждый из последующих уровней обслуживается предыдущим или нижележащим. Так образуются вертикальные межуровневые связи. Особенности обслуживания каждого уровня скрыты от остальных.

При взаимодействии двух сетей каждый из уровней одной сети контактирует с аналогичным уровнем другой. Так образуются горизонтальные связи.

Управление микроконтроллером

Управление МК может осуществляться двумя способами:

  1. Проводной путь. Управление исполнительными механизмами происходит через электропроводное соединение управляющих цепей и исполнительных механизмов. Включение — по нажатию кнопки на диспетчерском пункте или кнопочном пульте.
  2. Беспроводной путь. Такой способ управления не требует проводного соединения. С передатчика или пульта дистанционного управления (ПДУ) передается сигнал, который идет на приемник.

Сигналы беспроводного соединения могут быть:

  • Оптическими. Подобными сигналами управляется домашняя бытовая техника: телевизоры или кондиционеры.
  • Радио. Есть несколько вариантов: Wi-Fi, Bluetooth и др.

Развитие современных средств связи позволяет управлять контроллерами как через ПДУ, находясь в непосредственной близости к прибору, так и по интернету из любой точки мира через локальную сеть.

Обеспечивает поддержку cети Wi-Fi МК ESP 8266. В продаже он может быть в виде микросхемы или распаян, как arduino. У него 32-битное ядро, программировать его нужно через последовательный порт UART. Бывают более продвинутые платы с возможностью прошивки по USB – это NodeMCU. Они могут хранить информацию, записанную, например, с датчиков. Такие платы работают с различными интерфейсами, в т. ч. SPI, I2S.

Поддерживает большое число функций:

  • планировщик задач;
  • таймер;
  • канал АЦП;
  • формирование на выходе ШИМ сигнала;
  • аудиопроигрыватель и многое другое.

Плата может быть использована как самостоятельное устройство и как модуль для беспроводной связи с Ардуино.

Тактирование микроконтроллеров

Тактовая частота МК – это количество тактов за секунду, выполняемых контроллером. Чем она выше, тем большее количество операций он может выполнить.

Микроконтроллеры

Существуют несколько способов тактирования МК. Они зависят от использования:

  • Внутреннего RC-генератора. Он может работать только на частоте 1, 2, 4, 8 МГц. Если нужна другая частота, то он не подойдет. При необходимости использования точных временных интервалов тоже нельзя пользоваться этим методом, т. к. его задающая частота колеблется в зависимости от температуры.
  • Внешнего кварца. Этот способ имеет более сложное подключение. Емкость конденсатора должна находиться в интервале 15–22 пФ. Один выход присоединяется к резонатору, а другой заземляется.
  • Внешнего генератора. Этот генератор также нестабилен при разной температуре, как и внутренний.
  • RС-цепочек. Для данной схемы подойдет конденсатор емкостью от 22 пФ, резистор 10–100 кОм.

Для простейших микроконтроллеров подойдут внутренний или внешний генератор и RC-цепочки. Для проектирования более точных МК потребуются стабильные источники тактирования.

Семейства микроконтроллеров

Все МК объединяются в семейства. Основная характеристика, по которой происходит это деление, — структура ядра.

 Под ядром МК подразумевают набор определенных команд, цикличность работы процессора, организацию как памяти программ, так и баз данных, систему прерываний и базовый набор периферийных устройств (ПУ).

Различаются представители одного семейства между собой объемом памяти программ и баз данных, а также разнообразием ПУ.

Объединяют все МК в семейства одинаковость двоичного кода программирования.

Семейства делятся на:

  • MSC-51, производства Intel. Монокристальный МК на основе Гарвардской архитектуры. Основной представитель этого семейства 80С51, созданный по технологии CMOS. И хотя эти контроллеры разработаны еще в 80-х годах прошлого века, но до сих пор широко применяются. И сегодня многие компании, такие как Siemens, Philips и др. выпускают свои контроллеры с подобной архитектурой.
  • PIC (Microchip). МК Гарвардской архитектуры. В его основе лежит архитектура с сокращенным набором команд, встроенная память команд и данных, низкое энергопотребление. В это семейство входят более 500 различных МК (8-ми, 16-ти, 32-битные) с различными наборами периферии, памяти и прочими характеристиками.
  • AVR (Atmel). Высокоскоростные контроллеры разработаны на собственной архитектуре. Основой контроллера является Гарвардский RISC-процессор с самостоятельным доступом к памяти программ и баз данных (Flash ПЗУ). Каждый из 32 регистров общего назначения может работать как регистр-аккумулятор и совокупность 16-битных команд. Высокая производительность в 1 MIPS на каждый МГц тактовой частоты обеспечивается за счет порядка выполнения команд, который предусматривает выполнение одной команды и одновременную подготовку к следующей. Для поддержания своей продукции компания Atmel выпускает бесплатную и качественную среду разработки Atmel
  • ARM (ARM Limited) разработаны на собственной архитектуре. В семейство входят 32-х и 64-битовые МК. ARM Limited занимается только разработкой ядер и их инструментов, а лицензии на производство продает другим компаниям. Эти процессоры потребляют мало энергии, поэтому находят широкое применение в производстве мобильных телефонов, игровых консолей, маршрутизаторов и т. д. К компаниям, выкупившим лицензии, относятся: STMicroelectronics, Samsung, Sony Ericsson и др.
  • STM (STMicroelectronics). 8-разрядные контроллеры (STM8) относятся к категории высоконадежных с низким энергопотреблением изделий. В это же семейство входят контроллеры STM32F4 и STM Их основу составляет-32 битный Cortex. Такие контроллеры обладают отлично сбалансированной архитектурой и имеют большие перспективы развития.

Это не все семейства микроконтроллеров. Здесь мы привели только основные.

Типы корпусов микроконтроллеров

Внешних отличий МК от других микросхем нет. Кристаллы размещены в корпусах с определенным количеством выходов. Все МК выпускаются только в 3-х типах корпусов:

  • Корпус DIP имеет два ряда выводов. Расстояние между ними 2,54 мм. Выводы вставляются внутрь отверстий на контактных площадках.
  • Корпус SOIC. Он подходит для монтажа, который предполагает поверхностную припайку выходов к контактной площадке. Расстояние между выходами 1,27 мм.
  • Корпуса QFP (TQFP). Выводы расположены со всех сторон. Расстояние между ними в 3 раза меньше, чем в DIP. Корпус имеет квадратную форму. Предназначаются только для поверхностной пайки.
  • Корпус QFN. Самый маленький по сравнению с предыдущими. Контакты выходят в 6 раз чаще, чем в DIP. Имеют большое распространение в промышленном производстве, т. к. позволяют значительно уменьшить габариты выпускаемых приборов.

Микроконтроллер в корпусе QFP

Каждый из корпусов имеет свои точки применения. Первые 3 могут использоваться радиолюбителями.

В чем отличие микроконтроллера от микропроцессора?

Весь компьютерный функционал микропроцессора (Micro Processor Unit — MPU) содержится на одном полупроводниковом кристалле. По характеристикам он соответствует центральному процессору компьютера ЦП (Central Processing Unit — CPU). Область его применения – хранение данных, выполнение арифметико-логических операций, управление системами.

МП получает данные с входных периферийных устройств, обрабатывает их и передает выходным периферийным устройствам.

Микроконтроллер совмещает в себе микропроцессор и необходимые опорные устройства, объединенные в одном чипе. Если нужно создать устройство, коммуницирующее с внешней памятью или блоком ЦАП/АЦП, то понадобится только подключить источник питания с постоянным напряжением, цепь сброса и источник тактовой частоты.

Устройства на микроконтроллерах

Каждый из видов контроллеров имеет свои периферические устройства, которые работают автономно, т. е. независимо от центрального ядра. После того как периферийное устройство выполнит свою задачу, оно может сообщить об этом ЦП, а может и не сообщать. Это зависит от того, как оно запрограммировано.

На МК могут быть следующие устройства:

  • Аналоговый компаратор. Основная его задача сравнивать поступающее (измеряемое) напряжение с идеальным. Если измеряемое напряжение выше, чем идеальное, то компаратор выдает сигнал логической 1 (прибор отключается), если ниже, то логический 0 (прибор продолжает работать).
  • Аналогово-цифровой преобразователь (АЦП). Измеряет аналоговое напряжение в период времени и выдает его в цифровой форме. Есть не у всех МК.
  • Таймер/счетчик. Представляет собой сочетание 2-х форм таймера и счетчика. Таймер формирует интервалы времени, а цифровой счетчик считает количество импульсов, идущих от внутреннего генератора частот, или сигналы от внешних источников. Одним из представителей работы таймера /счетчика может быть ШИМ (широтно-импульсный модулятор). Он предназначен для управления средним значением напряжения при нагрузке.
  • Сторожевой таймер. Его задача перезапускать программу через определенный временной промежуток.
  • Модуль прерываний. Он сообщает МК о наступлении какого-либо события и прерывает выполнение программы. После завершения события возобновляет прерванную программу.

Не все из этих периферийных устройств обязательно есть в каждом МК. Существуют и другие, менее распространенные устройства.

Что нужно для программирования микроконтроллера

Чтобы микроконтроллер мог выполнять необходимые функции и решать определенные задачи, его необходимо запрограммировать.

Путь программирования проходит несколько этапов:

  1. Перед тем как приступить к написанию кода программы, надо определиться с конечной целью.
  2. Составляется алгоритм работы программы.
  3. Непосредственное написание кода программы. Коды пишутся на языке Си или Ассемблере.
  4. Компиляция программы, т. е. перевод ее в двоичную или шестнадцатеричную систему 1 и 0. Только так ее сможет понять МК.
  5. Откомпилированный код записывают в память контроллера.
  6. Прошивают МК с помощью программатора. Они бывают двух типов подключения: через COM или USB порт. Самый простой и дешевый программатор USBASP.
  7. Тестирование и отладка МК на реальном устройстве.

Программирование микроконтроллеров

Радиолюбители иногда обходятся без прописывания алгоритма работы программы на бумаги. Они держат его в голове.

Языки программирования

Языки программирования для МК мало чем отличаются от классических компьютерных. Основное отличие заключается в том, что МК ориентируются на работу с периферией. Архитектура МК требует битово-ориентированных команд. Поэтому для контроллеров создавались особые языки:

  • Ассемблер. Самый низкий уровень языка. Программы, написанные на нем, получаются громоздкими и труднопонимаемыми. Но несмотря на это он позволяет наиболее полно раскрыть все возможности контроллеров и получить максимальное быстродействие и компактный код. Подходит преимущественно для маленьких 8-битных МК.
  • С/С++. Более высокий уровень языка. Программа, написанная на нем, более понятна человеку. На сегодняшний день есть много программных средств и библиотек, позволяющих писать коды на этом языке. Его компиляторы есть практически на любой модели МК. На сегодня это основной язык для программирования контроллеров.
  • Еще более удобный для восприятия и проектирования язык. Но он мало применяется для программирования МК.
  • Старинный язык программирования. На сегодня почти не применяется.

Выбор языка для программирования зависит от решаемых задач и необходимого качества кода. Если нужен компактный код, то подойдет Ассемблер, для решения более глобальных задач выбор ограничится только С/С++.

Среда разработки

На сегодня нельзя найти универсальной среды для программирования МК. Это связано с его внутренней структурой и наличием технического обеспечения записи кода в память контроллера.

Вот несколько сред программирования:

  • FlowCode – универсальная графическая среда. Программируется с помощью построения логических структур блок-схем.
  • Algorithm Builder. Тоже графическая среда. Но написание кода проходит в 3–5 раз быстрее, чем в FlowCode. В ней совмещены графический редактор, компилятор, симулятор МК, внутрисхемный программатор.
  • В ней объединены Ассемблер и С/С++. Функционал среды позволяет самостоятельно прошивать МК.
  • Image Craft. Как и предыдущая поддерживает Ассемблер и С/С++ языки. В ее составе есть библиотека, позволяющая работать с отдельными устройствами МК.
  • Популярная среда для любителей. Имеет Си-подобный язык, но отличающийся от других. Он более понятен человеку. Поддерживает библиотеки, в составе которых есть драйвера для подключения некоторых платформ.

Среды бывают платные и бесплатные. Выбирая конкретную среду, нужно исходить из ее функционала, языка программирования, поддерживаемых интерфейсов и портов.

Основы программирования

Прежде чем приступать к программированию МК, нужно выбрать язык. Начинать лучше с Ассемблера. Хотя для понимания он достаточно сложен, но если приложить силы и все-таки понять его логику, то тогда станет ясно, что именно происходит в контроллере.

Программирование

Если Ассемблер окажется сложен, то можно начинать с Си. Одной из сильных его сторон является то, что он хорошо переносит коды с одного вида МК на другой. Но для этого надо правильно все прописать, разделив рабочие алгоритмы и их реализации в машине по разным частям проекта. Это позволит переносить алгоритм в другой контроллер, переделав всего лишь интерфейсный слой, в котором прописано обращение к «железу», оставив рабочий код без изменений.

Далее действуют по следующей схеме:

  1. Выбор компилятора и установка среды (подробнее о них писалось выше).
  2. Запуск среды и выбор в ней нового проекта. Необходимо будет указать место расположения. Путь нужно выбирать наиболее короткий.
  3. Настройка проекта. Классическим действием будет создание make-файла, в котором прописываются все зависимости. На первой странице указывают еще частоту работы МК.
  4. Настройка путей. В них надо добавить директорию проекта. В нее можно добавлять сторонние библиотеки.
  5. Постановка задачи.
  6. Сборка схемы. На этом этапе надо соединить модуль USB-USART конвертера с аналогичными выводами МК. Это позволит прошить микроконтроллер без программатора. Нужно накинуть джамперы, соединяющие LED1 и LED2. Этим действием мы подключим светодиоды LED 1 и 2 к выводам PD4 и PD5.
  7. Пропись кода.
  8. Добавление библиотек и заголовков с определениями.
  9. Главные функции. Язык Си состоит из одних функций. Они могут быть вложенными и вызываться в любом порядке относительно друг из друга и разными способами. Но все они имеют три обязательных параметра: 1) возвращаемое значение; 2) передаваемые параметры; 3) тело функции. В зависимости отданных, все возвращаемые или передаваемые значения должны быть определенного типа.
  10. Компиляция и запуск эмуляции.
  11. Отладка программы.

После того как прописали программу на языке Си, можно понаблюдать, как и что происходит в МК. Это поможет выстроить аналогию с программированием на Ассемблере.

Советы начинающим программистам микроконтроллеров

Чтобы первый опыт в программировании МК не закончился неудачей и навсегда не отбил охоту заниматься этим делом, нужно следовать некоторым советам:

  • Начинать с изучения периферии и ее особенностей.
  • Каждую большую задачу надо разделять на максимально количество мелких.
  • В начале пути не стоит упрощать себе жизнь и пользоваться кодогенераторами, нестандартными фичами и т. п. вещами.
  • Обязательно нужно изучать языки программирования (Си и Ассемблера).
  • Читайте Даташит.
  • Соберите необходимый набор инструментов. Это стоит определенных денег, но окупит себя экономией времени и качеством работы.

Никогда не поздно стать радиолюбителем, будь вам 30 лет или 50. И необязательно иметь профильное высшее образование. Сейчас на просторах интернета много доступной информации, изучая которую можно разобраться в устройстве микроконтроллеров и научиться их программировать.

Структура WAV плеера
Окончательный вариант звонка был создан в несколько этапов, причем изначально я не намеревался всерьез делать данное устройство, просто иногда возникали мысли типа: а неплохо было бы разработать свой вариант проигрывателя музыкальных файлов с использованием карты памяти…

Все началось с изучения основных команд для работы с картой памяти MMC, это команды сброса, инициализации, чтения и т.д., причем все эти команды поддерживаются и SD картами. Для практической тренировки я решил собрать устройство для вывода картинок с карты памяти на дисплей Nokia 1110i. В качестве микроконтроллера был выбран PIC16F628A. Сначала я работал без файловой системы FAT, то есть записывал байты картинок в определенную область карты памяти, а точнее в область данных файловой системы. Картинка имела фиксированный адрес, по которому микроконтроллер считывал ее. Кстати записать данные на карту памяти по любому адресу можно с помощью программы WinHex.

Далее я начал изучать файловую систему FAT16, и написал новый код для микроконтроллера. Теперь можно было просто записать бинарный файл с картинками на карту памяти при помощи компьютера, а микроконтроллер находил этот файл по имени и расширению, используя возможности файловой системы.

Прошло некоторое время, и я решился уже сделать проигрыватель музыкальных файлов. На этот раз взял микроконтроллер помощнее PIC16F876A, у которого достаточно много ОЗУ и большая память программ, а также присутствуют множество периферийных модулей. К микроконтроллеру для удобства подключил дисплей от Nokia, для вывода имен файлов имеющихся на карте памяти, а также отображения различных ошибок. Музыкальными файлами являлись самые простые WAV файлы, которые использовались в других подобных устройствах найденных в сети. Итак, я написал новый код и прилепил к нему предыдущие наработки по работе с файловой системой. В качестве цифро-аналогового преобразователя для вывода звука в первое время использовал R-2R матрицу, составленную из резисторов, так как количество линий микроконтроллера позволяло использование такой матрицы. В дальнейшем под это дело начал использовать ШИМ модуль. Первоначально на дисплей выводились короткие имена файлов в формате 8.3, немалыми усилиями был расшифрован алгоритм записи длинных имен в системе FAT, после чего я подправил код микроконтроллера и теперь можно было лицезреть полные имена файлов на дисплее.

По прошествии еще некоторого количества времени, у меня появилась мысль: а не получится ли запихнуть этот код, убрав все лишнее в тот самый PIC16F628A? Естественно от дисплея пришлось отказаться, и вместе с ним сократился объем кода, путем выпиливания больших таблиц знакогенератора. И наконец, мне удалось перенести устройство на другой микроконтроллер.

В предлагаемом звонке для хранения мелодий используются карты памяти SD или MMC, отформатированные под файловую систему FAT16 (c 2018 года есть версия с поддержкой файловой системы FAT32 и карт памяти SDHC, подробней в конце статьи). В качестве мелодий используются звуковые файлы формата WAV. Устройство может воспроизводить большое количество мелодий, а также его можно использовать в качестве простого проигрывателя WAV файлов.
Устройство собрано на широко распространенном микроконтроллере PIC16F628A, и имеет два режима работы, которые устанавливаются с помощью переключателя SA1. Верхнему положению переключателя соответствует режим “Проигрыватель”, а нижнему режим “Звонок”. Микроконтроллер проверяет состояние переключателя только один раз, после подачи питания. Для смены режима необходимо отключить питание, установить переключатель в требуемое положение, и снова подать питание на устройство.
Схема WAV проигрывателя
На транзисторе VT1 собран управляемый стабилизатор напряжения на 3,3В, для питания карты памяти. Управление стабилизатором осуществляется по линии порта RA3, при низком логическом уровне на этой линии транзистор VT1 закрыт, напряжение на его эммитере равно нулю. При высоком логическом уровне на линии, транзистор открывается, тем самым подавая питание на карту памяти. Напряжение на базе транзистора стабилизируется стабилитроном VD1.

В режиме “Звонок” после подачи питания, микроконтроллер производит настройку внутренних регистров, после чего переходит в спящий режим. При нажатии кнопки SB1 (“Звонок/Воспроизведение”), микроконтроллер “просыпается”, о чем свидетельствует включение светодиода HL1, включает питание карты памяти, сбрасывает и инициализирует ее, далее ищет на ней звуковой файл. Поиск мелодий осуществляется по расширению WAV. Найдя нужный файл, микроконтроллер воспроизводит его, отключает питание карты памяти, после чего снова “засыпает”, а светодиод HL1 гаснет. При следующем нажатии на кнопку SB1 все повторится, но будет воспроизведен следующий звуковой файл.

На карту памяти можно записать до 512-ти мелодий, это максимальное количество записей в корневом каталоге для файловой системы FAT16. После воспроизведения всех мелодий, начнется их повторное проигрывание. Кнопки SB2, SB3, SB4 в этом режиме не задействованы.

В режиме “Проигрыватель” после подачи питания микроконтроллер также выполняет настройку внутренних регистров, включает питание карты памяти, производит процедуру ее сброса и инициализации, в случае успешного выполнения процедуры вспыхивает светодиод HL1. Далее выполняется поиск WAV файла, как только файл будет найден, микроконтроллер перейдет к опросу состояния кнопок.
При нажатии кнопки SB1 начнется непрерывное воспроизведение всех звуковых файлов имеющихся на карте памяти. Кнопкой SB2 (“Стоп”) можно остановить проигрывание на текущей мелодии, кнопками SB3 (“Следующий”) и SB4 (“Предыдущий”) переключаются между мелодиями, переключение возможно при проигрывании, а также после остановки.

При неудачной процедуре сброса и инициализации карты памяти, микроконтроллер предпримет еще одну попытку, и если она также будет неудачной, прозвучат два коротких сигнала низкого тона, после чего микроконтроллер уйдет в круговой цикл, и перестанет отвечать на команды. В этом случае необходимо проверить надежность соединения с картой памяти, или попробовать заменить ее. В режиме “Звонок”, при ошибке сброса и инициализации, также прозвучат два коротких сигнала низкого тона, после чего, как и прежде микроконтроллер отключит питание карты и перейдет в спящий режим. Если карта памяти перестанет отвечать на команды или просто “зависнет”, то в режиме “Проигрыватель”, микроконтроллер отключит и включит питание карты, затем заново сбросит и проинициализирует ее. В режиме “Звонок”, после “зависания” карты, микроконтроллер просто отключает питание карты и “засыпает”. При отсутствии WAV файлов на карте памяти, прозвучат три коротких сигнала низкого тона, после чего “Проигрыватель” перейдет к опросу кнопок, при нажатии которых будет звучать тот же предупреждающий сигнал, а в режиме “Звонок”, после сигнала об отсутствии файлов, микроконтроллер отключит питание карты памяти и “заснет”. Если параметры WAV файла не будут соответствовать требуемым значениям, например, неверная частота дискретизации, разрядность и т.д., прозвучит сигнал низкого тона длительностью в одну секунду, и в обоих режимах произойдет переход к следующей мелодии.

Для согласования логических уровней микроконтроллера и карты памяти, установлены делители напряжения на резисторах R6-R11.

Звук выводится с помощью востренного в микроконтроллер модуля ШИМ, частота которого в данном устройстве равна 78,12кГц. Звуковой сигнал сглаживается фильтром R14C9, далее поступает на усилитель мощности, построенный на микросхеме DA1 TDA2003. Переменным резистором R18 регулируют громкость звука. Элементы R15, C11 необходимо установить при самовозбуждении усилителя.

Устройство поддерживает звуковые файлы формата WAV (PCM, 16кГц, 8 бит, моно, несжатый), файлы с другими параметрами проигрываться не будут, поэтому, если необходимо, выбранные звуковые файлы преобразуют с помощью программ-конвертеров. При записи на карту памяти, WAV файлы могут иметь любые имена.

Файловая система FAT16 не поддерживает носители информации имеющие объем больше 2 Гб, поэтому это максимальный объем для карты памяти, которую можно использовать в устройстве. Были протестированы 4 карты формата microSD, разных фирм и объемов, это Kingston 1GB, Kingmax 512MB, Silicon Power 2GB, Transcend 1GB. MMC карты также должны работать, я не смог это проверить, из-за отсутствия такой карты.

В устройстве применены постоянные резисторы МЛТ. Переключатель SA1 – ПД 9-2. Кнопки SB1-SB4 тактовые TS-A3PS-130. Стабилитрон КС139А можно заменить на импортный, с напряжением стабилизации 3,9В. Динамическую головку BA1 можно использовать любую, мощностью 2 – 4 Вт с сопротивлением катушки 4 или 8 Ом. Вместо транзистора КТ503В можно установить КТ3102АМ. Микросхема TDA2003 заменима на TDA2002, TDA2008, К174УН14, ее необходимо установить на теплоотвод площадью не менее 60 см2.

Все детали размещены на печатной плате из односторонне фольгированного стеклотекстолита. На печатной плате предусмотрены отверстия для подключения внешней кнопки “Звонок”, которая дублирует кнопку SB1. Разъем для карты памяти самодельный. В качестве источника питания можно использовать нестабилизированный сетевой блок питания с выходным напряжением 9–12В и током не менее 0,5А. Программа для микроконтроллера написана на ассемблере в среде MPLAB.
Внешний вид WAV проигрывателя
Я заметил, что у некоторых людей возникают проблемы при повторении устройства, а именно звучит сигнал низкого тона длительностью в одну секунду, указывая на неправильные параметры WAV файла. Поэтому скажу немного о структуре WAV файла.
У каждого WAV файла в заголовке есть идентификатор в виде слова WAVE, а также идентификатор в виде слова data, а также есть такие параметры как: частота дискретизации, разрядность, параметр – сжатый/несжатый, параметр – моно/стерео. У файла должны быть правильные параметры указанные выше в статье. Если параметры не будут совпадать или микроконтроллер не найдет идентификаторы WAVE и data, появится сигнал об ошибке. Некоторые программы – конвертеры, возможно, записывают неправильные параметры. Поэтому если появляется ошибка, надо попробовать другую программу, я например, использовал Sound Forge. Также ниже можно скачать тестовые музыкальные файлы.

Статья опубликована в журнале “Радио” №4 за 2012 год под названием «Музыкальный звонок на микроконтроллере».

Рисунок платы в формате JPG
Печатная плата в формате Sprint Layout
Вариант печатной платы от пользователя (MIR&Co), формат Sprint Layout
Печатная плата от пользователя (Михаил), формат Sprint Layout

Прошивка МК и исходник
Тестовые WAV файлы

Ниже представлена обновленная версия прошивки. В этой версии в EEPROM микроконтроллера сохраняется номер проигранной мелодии (только для режима звонка). Таким образом после пропадания питания проигрывание начнется не с первой мелодии из папки, а продолжится с момента сохранения.

Версия прошивки с сохранением номера мелодии в EEPROM

Обновление: мной разработана новая прошивка с поддержкой карт памяти SDHC и файловой системы FAT32, можно использовать карты емкостью 4-32ГБ, за прошивку я беру небольшую плату, связаться со мной можно по контактам указанным на странице Об авторе

Понравилась статья? Поделить с друзьями:
  • Как позвонить микрозайм деньга
  • Как позвонить микроволновую печь
  • Как позвонить мие бойке
  • Как позвонить миграционную службу сахарово
  • Как позвонить механику на радмир рп