Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 14.05.2020
Сообщений: 4
1

Частотомер на ATmega128

15.05.2020, 01:02. Просмотров 580. Ответов 25

Здравствуйте, не могу разобраться в чем проблема. Написан код для того, что бы на выход PB4 подавался ШИМ сигнал, а с входа PD6 считывалась частота и всё это выводилось на ЖКИ. При подключении в протеусе у соответствующих портов мигают идикаторы, то есть сигнал приходит, но на ЖКИ ничего не выводится

C
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
//библиотека хранящая адреса портов
#include <avr/io.h>
// Частота МК
#define F_CPU 10000000UL
#include <util/delay.h>
//библиотека для функций прерывания
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
 
//инициализация переменных, хранящих численное значение
//частоты сигнала
uint32_t f = 0;
//инициализация массива для вывода числа(частоты) на дисплей
char arr_f[10];
//переменная для отсчета времени в 100мс для вывода информации на дисплей
//и подсчета кол-ва инпульсов
uint32_t timer = 0, timer2 = 0;
 
//Для доступа к портам avr atmega заведем макросы:
 
//линии данных
#define LCD_DATA       PORTC
#define LCD_DATA_DDR   DDRC
 
//управляющие линии
#define LCD_CTRL       PORTC
#define LCD_CTRL_DDR   DDRC
 
 
#define LCD_RS_DATA     0x01    // 1 - данные
#define LCD_RS_COMMAND  0x00    // 0 - команды
#define LCD_E           0x02
/*выставить в 1 линию E импульс длительностью не менее 500 мс
 на этом выводе определяет сигнал для чтения данных с выводов DB0-DB7, RS и W/R*/
#define lcd_set_e   LCD_CTRL |= LCD_E
/*выставить в 1 линию RS означает, что сигнал на выходах DB0-DB7 является данными*/
#define lcd_set_rs  LCD_CTRL |= LCD_RS_DATA
 
/*выставить в 0 линию E импульс длительностью не менее 500 мс на этом выводе
 определяет сигнал для записи данных с выводов DB0-DB7, RS и W/R*/
#define lcd_clear_e  LCD_CTRL &= ~LCD_E
/*выставить в 0 линию RS означает, что сигнал на выходах DB0-DB7 является командой*/
#define lcd_clear_rs LCD_CTRL &= ~LCD_RS_DATA
//rw = 0,(он заземлен) т.е. все врем производится запись.
 
//Для облегчения настройки контроллера hd44780 заведем макросы, описывающие систему команд:
/*Очистить дисплей*/   //    Очистка экрана, AC=0, адресация AC на DDRAM
#define LCD_CLR              1<<0
/*Переход в начало экрана*/
//AC=0, адресация на DDRAM, сброшены сдвиги, начало строки адресуется в начале DDRAM
#define LCD_HOME             1<<1
 
#define LCD_MODE             1<<2 /*Сдвиг курсора или экрана при записи символа*/
#define LCD_MODE_SHIFT       1<<0 //включение движения
#define LCD_MODE_INC         1<<1 //движение в увеличение
#define LCD_MODE_DEC         0<<1 //движение в уменьшение
#define LCD_MODE_OFF_SHIFT   0<<0 //выключение движения
 
#define LCD_ON               1<<3 /*Вкл/выкл дисплей, курсор, мигание*/
#define LCD_ON_DISPLAY       1<<2 //Наличие изображения: 1 — включено
#define LCD_ON_CURSOR        1<<1 //Курсор в виде символа подчеркивания: 1 — включен
#define LCD_OFF_CURSOR       0<<1 //Курсор в виде символа подчеркивания: 0 — выключен
#define LCD_ON_BLINK         1<<0 //Курсор в виде мерцающего знакоместа: 1 — включен
#define LCD_OFF_BLINK        0<<0 //Курсор в виде мерцающего знакоместа: 0 — выключен
 
#define LCD_SHIFT            1<<4 /*Команда сдвига курсора/экрана*/
#define LCD_SHIFT_DISPLAY    1<<3 //Определяет объект смещения: 1 — сдвигается экран
#define LCD_SHIFT_CURSOR     0<<3 //Определяет объект смещения: 0 — сдвигается курсор
#define LCD_SHIFT_RIGHT      1<<2 //Уточняет направление сдвига: 1 — вправо
#define LCD_SHIFT_LEFT       0<<2 //Уточняет направление сдвига: 0 — влево
 
#define LCD_FUNCTION         1<<5 /*Разрядность шины данных, кол-во строк, размер шрифта*/
#define LCD_FUNCTION_4BIT    0<<4 //Флаг, определяющий ширину шины данных: 0 — 4 разряда
#define LCD_FUNCTION_8BIT    1<<4 //Флаг, определяющий ширину шины данных: 1 — 8 разрядов
#define LCD_FUNCTION_1LINES  0<<3 //Режим развертки изображения на ЖКИ: 0 — одна строка
#define LCD_FUNCTION_2LINES  1<<3 //Режим развертки изображения на ЖКИ: 1 — две строки
#define LCD_FUNCTION_8DOTS   0<<2 //Размер матрицы символов: 0 — 5x8 точек
#define LCD_FUNCTION_10DOTS  1<<2 //Размер матрицы символов: 1 — 5x10 точек
 
#define LCD_SET_CGRAM        0x40 /*Присвоение счетчику курсора адреса в области CGRAM*/
 
#define LCD_SET_DDRAM        0x80 /*Присвоение счетчику курсора адреса в области DDRAM*/
 
/*Функция ожидания готовности контроллера hd44780. Можно считывать статусный бит,
но мы будем просто делать паузу, в течение которой команда будет гарантированно выполнена.*/
#define lcd_wait     _delay_us(50);
 
/* Макрос перемещения курсора в начальную  позицию (0, 0) */
#define lcd_home      lcd_data(0x02, LCD_RS_COMMAND);
 
 
/* инициализация портов,
подключенных к жки */
#define init_port\
    LCD_DATA_DDR = 0xFF;\
    LCD_DATA = 0x00;\
    LCD_CTRL_DDR = 0xFF;\
    LCD_CTRL = 0x00;
 
 
/* функция передачи тетрады в жки. передается
младшая тетрада входного байта */
void lcd_low_data(char t)
{
    t <<= 4;
    lcd_set_e;
    LCD_DATA &= 0x0F;
    LCD_DATA |= t;
    lcd_wait;
    lcd_clear_e;
    lcd_wait;
}
 
/* функция передачи байта в жки */
void lcd_data(char c, char rs)
{
    char highc = 0;
    highc = c >> 4;
    if (rs == LCD_RS_COMMAND)
    {
        lcd_clear_rs;
    }
    else
    {
        lcd_set_rs;
    }
    lcd_low_data(highc);
    lcd_low_data(c);
}
 
/* функция очистки дисплея и возврата
курсора в начальную позицию*/
void lcd_clear()
{
    lcd_data(0x01, LCD_RS_COMMAND);
    _delay_us(1500);
}
 
 
/* функция перемещения курсора в заданную позицию*/
void lcd_goto(char x, char y)
{
    char cursor;
    y &= 1;
    cursor  = 0x40 * y + x;
    cursor |= LCD_SET_DDRAM;
    lcd_data(cursor, LCD_RS_COMMAND);
}
 
 
//Макрос вывода символа на дисплей.
void lcd_putc(char x)
{
    lcd_data(x, LCD_RS_DATA);
}
 
 
//Функция вывода строки.
void lcd_puts( char *str)
{
  while( *str )
  {
    lcd_putc( *str++ );
  }
}
 
 
 
/* функция инициализации работы жки в 4-битном режиме, без курсора */
void lcd_init()
{
    _delay_ms(100);
    // Сброс шины данных
    lcd_clear_rs; // установка нуля на линии RS
 
    lcd_low_data(0x00);
    _delay_ms(5);
    lcd_low_data(0x00);
    _delay_ms(5);
    lcd_low_data(0x00);
    _delay_ms(5);
    lcd_low_data(0x00);
    _delay_ms(5);
    lcd_low_data(0x00);
    _delay_ms(5);
 
    // физический выбор шины, дисплея
    lcd_low_data(0x02);
    lcd_low_data(0x02);
    lcd_low_data((LCD_FUNCTION | LCD_FUNCTION_4BIT | LCD_FUNCTION_2LINES | LCD_FUNCTION_8DOTS) & 0x0F);
    // Здесь должна быть проверка флага занятости
    _delay_ms(50);
 
    // Display ON/OFF Control
    lcd_data((LCD_ON | LCD_ON_DISPLAY | LCD_OFF_CURSOR | LCD_OFF_BLINK), LCD_RS_COMMAND);
    // Здесь должна быть проверка флага занятости
    _delay_ms(50);
 
    // Очистка дисплея
    lcd_clear();
    // Здесь должна быть проверка флага занятости
    _delay_ms(50);
 
    // Режим вывода
    lcd_data((LCD_MODE | LCD_MODE_INC), LCD_RS_COMMAND);
 
    // Дополнительно: возврат в координату (0, 0)
    lcd_home;
 
    lcd_set_rs;
}
 
//функция обработчик прерывания по переполнению
//счетного регистра таймера 1
ISR(TIMER?1?_OVF_vect)
{
    //условие на 500 переполнений
    if(timer2 == 500)
    {   //расчет значения частоты
        f = (uint32_t)((timer*F_CPU) / (timer2*256));
        //заполнение массива числом посимвольно
        itoa(f, arr_f, 10);
        //очистка дисплея ЖКИ
        lcd_clear();
        //курсор в 0-ю позицию первой строки
        lcd_goto(0 , 0);
        //вывод значения на дисплей
        lcd_puts(arr_f);
        //сброс таймера для отсчета периода времени
        timer2 = 0;
        //сброс счетчика кол-ва импульсов
        timer = 0;
        //сброс счетного регистра
        TCNT0 = 0;
    }
    else
    {   //счет кол-ва переполнений
        timer2++;
    }
}
 
//функция обработчик прерывания по внешнему запросу
ISR(INT?1?_vect)
{   //счет кол-ва импульсов
    timer++;
}
 
// Предварительная настройка таймера
void timer_init() {
    long int oc = 49999; // ввод переменной для OCR0;
    //Инициализация Т/С0
    TCCR0 = 0;
    //настройка ножки OC0 в работу, предделитель равен 1,
    TCCR0 =  (0 << COM01) | (1 << COM00) | (1 << WGM01) | (0 << WGM00) | (1 << CS00);
    //Выбор режима PWM и предделителя
    //устанавливаем период сигнала(для частоты 1кГц)
    OCR0 = oc;
    DDRB = (1 <<4 ); //инициализация порта OC0 на выход
}
 
void timer_init2() {
    //Инициализация T/C1
    TCCR1А = 0;
    //Внешний тактовый источник с вывода T1, режим СТС;
    TCCR1B = (1 << CS12) | (1 << CS11) | (1 << WGM12);
    TCCR1C = 0;
    OCR1A = 2500;
    // Разрешаем прерывание по достижению максимума
    TIMSK  = (1 << OCIE1A);
    ETIMSK = 0x00;
    //Инициализация T1 на вход
    PORTD = 0;
    DDRD = (1 << 6)
}
 
 
 
int main(void) {
    // Запрет прерываний
    cli();
    //инициализируем таймер
    timer_init();
    timer_init2();
    init_port;
    //инициализация ЖКИ
    lcd_init();
    //очистить дисплей
    lcd_clear();
    // Глобальное разрешение прерываний
    sei();
    // Рабочий цикл
    while(1)
    {
 
    }
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.05.2020, 01:02
Ответы с готовыми решениями:

Частотомер
Всем привет. Решил обзавестись сим девайсом, погуглив в инете и просмотрев несколько вариантов схем...

Частотомер.
Делаю частотомер для струнного датчика с автогенератором, сигнал на выходе 0,3 В прямоугольный от 2...

Частотомер
Помогите разобраться в схеме: http://i025.***********/1108/36/f927493416ca.jpg Вопросы: ...

Частотомер
Привет всем, есть программа таймера ( частотомера) написана на ассемблере, в протеусе проверил сам...

25
1122 / 482 / 205
Регистрация: 11.10.2018
Сообщений: 2,717
24.05.2020, 13:54 21
Заработало, наконец-то!!!!!!!!!
0
1122 / 482 / 205
Регистрация: 11.10.2018
Сообщений: 2,717
24.05.2020, 14:36 22
А как увидеть переменную Counter? Почему он вот этот бред пишет?
0
Миниатюры
Частотомер на ATmega128  
1122 / 482 / 205
Регистрация: 11.10.2018
Сообщений: 2,717
24.05.2020, 20:55 23
Ну вот я допилил, точнее подпилил код. Товарищи, кто хочет - доработайте его, пожалуйста. У меня не получилось, потому что AVR ограниченная платформа работает с 8- и 16-битными числами, а вот тут такие операции
C++
1
2
3
4
    //расчет значения частоты
    freq = delta * 25,6;
    freq *= 1e-6;
    freq = 1/freq;
- Микроконтроллер их не делает. Компилятор пишет Warnings и не компилиует их.
Весь код
Кликните здесь для просмотра всего текста

C++
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
#include <io.h>
#include <mega128a.h>
 
//библиотека хранящая адреса портов
//#include <avr/io.h>
// Частота МК
#define F_CPU 10000000UL
#include <delay.h>
//библиотека для функций прерывания
#include <interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
 
//инициализация переменных, хранящих численное значение
//частоты сигнала
unsigned long int f = 0;
unsigned long int delta = 0;
double freq = 0;
//2 байта
//unsigned int Counter = 0;
//инициализация массива для вывода числа(частоты) на дисплей
char arr_f[10];
//переменная для отсчета времени в 100мс для вывода информации на дисплей
//и подсчета кол-ва инпульсов
long int timer = 0, timer2 = 0;
bit First = 1;
 
//Для доступа к портам avr atmega заведем макросы:
 
//линии данных
#define LCD_DATA       PORTC
#define LCD_DATA_DDR   DDRC
 
//управляющие линии
#define LCD_CTRL       PORTC
#define LCD_CTRL_DDR   DDRC
 
 
 
#define LCD_PIN_RS         0
#define LCD_PIN_E          1
 
#define LCD_RS_DATA     0x01    // 1 - данные
#define LCD_RS_COMMAND  0x00    // 0 - команды
#define LCD_E           0x02
 
 
 
 
 
 
//Для облегчения настройки контроллера hd44780 заведем макросы, описывающие систему команд:
/*Очистить дисплей*/   //    Очистка экрана, AC=0, адресация AC на DDRAM
#define LCD_CLR              1<<0
/*Переход в начало экрана*/
//AC=0, адресация на DDRAM, сброшены сдвиги, начало строки адресуется в начале DDRAM
#define LCD_HOME             1<<1
 
#define LCD_MODE             1<<2 /*Сдвиг курсора или экрана при записи символа*/
#define LCD_MODE_INC         1<<1 //движение в увеличение
#define LCD_MODE_DEC         0<<1 //движение в уменьшение
#define LCD_MODE_SHIFT       1<<0 //включение движения
#define LCD_MODE_OFF_SHIFT   0<<0 //выключение движения
 
#define LCD_ON               1<<3 /*Вкл/выкл дисплей, курсор, мигание*/
#define LCD_ON_DISPLAY       1<<2 //Наличие изображения: 1 — включено
#define LCD_ON_CURSOR        1<<1 //Курсор в виде символа подчеркивания: 1 — включен
#define LCD_OFF_CURSOR       0<<1 //Курсор в виде символа подчеркивания: 0 — выключен
#define LCD_ON_BLINK         1<<0 //Курсор в виде мерцающего знакоместа: 1 — включен
#define LCD_OFF_BLINK        0<<0 //Курсор в виде мерцающего знакоместа: 0 — выключен
 
#define LCD_SHIFT            1<<4 /*Команда сдвига курсора/экрана*/
#define LCD_SHIFT_DISPLAY    1<<3 //Определяет объект смещения: 1 — сдвигается экран
#define LCD_SHIFT_CURSOR     0<<3 //Определяет объект смещения: 0 — сдвигается курсор
#define LCD_SHIFT_RIGHT      1<<2 //Уточняет направление сдвига: 1 — вправо
#define LCD_SHIFT_LEFT       0<<2 //Уточняет направление сдвига: 0 — влево
 
#define LCD_FUNCTION         1<<5 /*Разрядность шины данных, кол-во строк, размер шрифта*/
#define LCD_FUNCTION_4BIT    0<<4 //Флаг, определяющий ширину шины данных: 0 — 4 разряда
#define LCD_FUNCTION_8BIT    1<<4 //Флаг, определяющий ширину шины данных: 1 — 8 разрядов
#define LCD_FUNCTION_1LINES  0<<3 //Режим развертки изображения на ЖКИ: 0 — одна строка
#define LCD_FUNCTION_2LINES  1<<3 //Режим развертки изображения на ЖКИ: 1 — две строки
#define LCD_FUNCTION_8DOTS   0<<2 //Размер матрицы символов: 0 — 5x8 точек
#define LCD_FUNCTION_10DOTS  1<<2 //Размер матрицы символов: 1 — 5x10 точек
 
#define LCD_SET_CGRAM        0x40 /*Присвоение счетчику курсора адреса в области CGRAM*/
 
#define LCD_SET_DDRAM        0x80 /*Присвоение счетчику курсора адреса в области DDRAM*/
 
/*Функция ожидания готовности контроллера hd44780. Можно считывать статусный бит,
но мы будем просто делать паузу, в течение которой команда будет гарантированно выполнена.*/
#define lcd_wait     delay_us(800);
 
/* Макрос перемещения курсора в начальную  позицию (0, 0) */
#define lcd_home      lcd_data(0x02, LCD_RS_COMMAND);
 
 
//========================= LCD Fuctions =========================
/* инициализация портов,
подключенных к жки
#define init_port\
    LCD_DATA_DDR = 0xF0;\
    LCD_DATA = 0x00;\
    LCD_CTRL_DDR = 0x03;\
    LCD_CTRL = 0x00;
*/
void Init_Port(void)
{
    LCD_DATA_DDR = 0xF0;
    LCD_DATA = 0x00;
    LCD_CTRL_DDR |= 0x03;
    LCD_CTRL = 0x00;
}
//========================= Init LCD =========================
#define e1 PORTC |= 0b00000010 // установка линии E в 1  эту строку ставишь рядом с инклудами
 
#define e0 PORTC &= ~0b00000010 // установка линии E в 0  эту строку ставишь рядом с инклудами
 
#define rs1 PORTC |= 0b00000001 // установка линии RS в 1 (данные)  эту строку ставишь рядом с инклудами
 
#define rs0 PORTC &= ~0b00000001 // установка линии RS в 0 (команда)  эту строку ставишь рядом с инклудами
 
 
 
 
 
void sendhalfbyte(unsigned char c)  //служебная функция для работы библиотеки
{
    c<<=4;
    c &= 0xF0;
    e1;
    PORTC &= 0b00001111;
    PORTC |= c;
    delay_ms(1);
    e0;
    delay_ms(1);
} 
 
void sendbyte(unsigned char c, unsigned char mode)  //служебная функция для работы библиотеки
{
    unsigned char hc=0;
    
    if(mode == 0)
      rs0;
    else
      rs1;
    delay_us(50);
    hc = c>>4;
 
    sendhalfbyte(hc);
    sendhalfbyte(c);
} 
 
void sendbuk(unsigned char c)     //функция отправки по одной букве, например: sendbuk('E');
{
    sendbyte(c,1);
}
 
void mesto(unsigned char x, unsigned char y) //функция для установки курсора, например: mesto(0,0); - установит 
{                                                        //курсор в начало дисплея
    char address;
    address = (64*y+x)|0b10000000;
    sendbyte(address, 0);
}
 
void sendsl(char str1[])  //функция отправки слова, например: sendsl('privet');
{
    char n;
    for(n=0; str1[n]!=0; n++)
    sendbuk(str1[n]);
}
   
void Init_LCD(void)    //функция инициализации дисплея в 4 проводном режиме
{
    delay_ms(40); //Ждем 15 мс
 
    sendhalfbyte(0b00000011);
    delay_ms(1);
    sendhalfbyte(0b00000011);
    delay_ms(1);
    sendhalfbyte(0b00000011);
    delay_ms(1);
    sendhalfbyte(0b00000010);
    delay_ms(1);
    sendhalfbyte(0b00000010);
    delay_ms(1);
    sendhalfbyte(0b00000010);
    delay_ms(1);
    sendbyte(0b00101000, 0); //4бит-режим (DL=0) и 2 линии (N=1)
    delay_ms(1);
    sendbyte(0b00001100, 0); //включаем изображение на дисплее (D=1), курсоры никакие не включаем (C=0, B=0)
    delay_ms(1);
    sendbyte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
    delay_ms(1);
}
 
/* функция очистки дисплея и возврата
курсора в начальную позицию*/
void lcd_clear()
{
    sendbyte(0x01, LCD_RS_COMMAND);
    delay_us(1700);
}
 
 
 
 
 
 
 
 
//========================= Interrupts =========================
//функция обработчик прерывания по захвату
//Таймера 1
//Timer/Counter1 Capture Event
#pragma vector=12
__interrupt void Timer1_Capt(void)
{
    cli();
    
    if(First)
    {
      //f = Counter(2 байта) + ICR1(2 байта) - эта идея не оправдалась 
      f =  ICR1;
      First = 0;
      return;
    }   
    else
    {
      delta = ICR1;    
      delta -= f;
      f = 0;
      First = 0;
    }
    
    //расчет значения частоты
    freq = delta * 25,6;
    freq *= 1e-3;
    freq = 1/freq;    
    
    //f = (long int)((timer*F_CPU) / (timer2*256));
    //f = myicr;      //12345;
        
    //заполнение массива числом посимвольно
    itoa(freq, arr_f);
        
    //очистка дисплея ЖКИ
    lcd_clear();
        
    //курсор в 0-ю позицию первой строки
    //lcd_goto(0, 0);
    mesto(0, 0);
        
    //вывод значения на дисплей
    sendsl(arr_f);
        
        
        
    sei();    
    
}
 
//функция обработчик прерывания по переполнению Таймера 1
//Timer/Counter1 Overflow Event
#pragma vector=15
__interrupt void Timer1_Ovf(void)
{
    /*
    if(Counter == 65535)
    {
        Counter = 0;
        First = 1;
    }
    else
    {
        Counter++;
    }
    */
    f = 0;
    delta = 0;
    First = 1;
}
 
 
/*
//функция обработчик прерывания по внешнему запросу
#pragma vector=3
__interrupt void INT1_ISR(void)
{   
    //счет кол-ва импульсов
    timer++;
}
*/
 
 
 
 
 
//========================= Timers Init ========================= 
// Предварительная настройка таймера
void timer0_init()
{
    //Инициализация Т0
    //предделитель равен 32
    TCCR0 = (0 << CS02) | (1 << CS01) |  (1 << CS00);
    
    //настройка ножки OC0 в работу
    TCCR0 |= (0 << COM01) | (1 << COM00) | (1 << WGM01) | (0 << WGM00);
    
    //Выбор режима PWM и предделителя
    //устанавливаем период сигнала(для частоты 1кГц)
    OCR0 = 155;
    DDRB = (1 << 4);  //инициализация порта OC0 на выход
}
 
void timer1_init()
{
    //Инициализация T1
    TCCR1A = 0;
    //Внешний тактовый источник CLK = 10 Meg/256
    //No overflow
    //Input Capture
    TCCR1B = (1 << ICES1) | (1 << CS12) | (0 << CS11) |(0 << CS10);
    TCCR1C = 0;
    OCR1A = 2500;
    // Разрешаем прерывание по достижению максимума
    TIMSK  = (1 << TICIE1) | (1 << TOIE1);
    ETIMSK = 0x00;
    //Инициализация T1 на вход
    PORTD = 0;
    DDRD &= ~(1 << 4);
}
 
 
 
 
 
//========================= main ========================= 
void main(void)
{
    //Запрет прерываний
    cli();
    //инициализируем таймер
    timer0_init();
    timer1_init();
    
    /*
    //Настройка INT1
    EICRA = (1 << ISC11) | (1 << ISC10);
    EIMSK = (1 << INT1);
    */
    
    Init_Port();
    //инициализация ЖКИ
    Init_LCD();
    //очистить дисплей
    //lcd_clear();
    
    
    
    //функция передачи байта в жки */
    //void lcd_data(char c, char rs)
    //lcd_data('C', 1);
    
    //lcd_puts("Privet");
    
    
 
    mesto(0, 0);
    sendbuk('S');
    sendbuk('T');
    sendbuk('A');
    sendbuk('R');
    sendbuk('T');
    //mesto(0, 1);
    //sendsl("Proverka");
 
    // Глобальное разрешение прерываний
    sei();
    
    
    //Рабочий цикл
    while(1)
    {
    }
}


Добавлено через 24 минуты
Товарищ, автор темы, Вам обязательно, чтобы генератор был внутри микроконтроллера? - Из-за этого, кстати, могут быть ошибки измерений.
Можно вынести генератор из микроконтроллера?
0
2573 / 1165 / 152
Регистрация: 28.10.2011
Сообщений: 4,113
Записей в блоге: 6
25.05.2020, 01:49 24
Цитата Сообщение от FFPowerMan Посмотреть сообщение
C
1
freq = delta * 25,6
C
1
freq = delta * 25.6
0
1122 / 482 / 205
Регистрация: 11.10.2018
Сообщений: 2,717
25.05.2020, 11:16 25
Кликните здесь для просмотра всего текста
C++
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
#include <io.h>
#include <mega128a.h>
 
//библиотека хранящая адреса портов
//#include <avr/io.h>
// Частота МК
#define F_CPU 10000000UL
#include <delay.h>
//библиотека для функций прерывания
#include <interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
 
//инициализация переменных, хранящих численное значение
//частоты сигнала
unsigned long int f = 0;
unsigned long int delta = 0;
double freq = 0;
//2 байта
//unsigned int Counter = 0;
//инициализация массива для вывода числа(частоты) на дисплей
char arr_f[10];
//переменная для отсчета времени в 100мс для вывода информации на дисплей
//и подсчета кол-ва инпульсов
long int timer = 0, timer2 = 0;
bit First = 1;
 
//Для доступа к портам avr atmega заведем макросы:
 
//линии данных
#define LCD_DATA       PORTC
#define LCD_DATA_DDR   DDRC
 
//управляющие линии
#define LCD_CTRL       PORTC
#define LCD_CTRL_DDR   DDRC
 
 
 
#define LCD_PIN_RS         0
#define LCD_PIN_E          1
 
#define LCD_RS_DATA     0x01    // 1 - данные
#define LCD_RS_COMMAND  0x00    // 0 - команды
#define LCD_E           0x02
 
 
 
 
 
 
//Для облегчения настройки контроллера hd44780 заведем макросы, описывающие систему команд:
/*Очистить дисплей*/   //    Очистка экрана, AC=0, адресация AC на DDRAM
#define LCD_CLR              1<<0
/*Переход в начало экрана*/
//AC=0, адресация на DDRAM, сброшены сдвиги, начало строки адресуется в начале DDRAM
#define LCD_HOME             1<<1
 
#define LCD_MODE             1<<2 /*Сдвиг курсора или экрана при записи символа*/
#define LCD_MODE_INC         1<<1 //движение в увеличение
#define LCD_MODE_DEC         0<<1 //движение в уменьшение
#define LCD_MODE_SHIFT       1<<0 //включение движения
#define LCD_MODE_OFF_SHIFT   0<<0 //выключение движения
 
#define LCD_ON               1<<3 /*Вкл/выкл дисплей, курсор, мигание*/
#define LCD_ON_DISPLAY       1<<2 //Наличие изображения: 1 — включено
#define LCD_ON_CURSOR        1<<1 //Курсор в виде символа подчеркивания: 1 — включен
#define LCD_OFF_CURSOR       0<<1 //Курсор в виде символа подчеркивания: 0 — выключен
#define LCD_ON_BLINK         1<<0 //Курсор в виде мерцающего знакоместа: 1 — включен
#define LCD_OFF_BLINK        0<<0 //Курсор в виде мерцающего знакоместа: 0 — выключен
 
#define LCD_SHIFT            1<<4 /*Команда сдвига курсора/экрана*/
#define LCD_SHIFT_DISPLAY    1<<3 //Определяет объект смещения: 1 — сдвигается экран
#define LCD_SHIFT_CURSOR     0<<3 //Определяет объект смещения: 0 — сдвигается курсор
#define LCD_SHIFT_RIGHT      1<<2 //Уточняет направление сдвига: 1 — вправо
#define LCD_SHIFT_LEFT       0<<2 //Уточняет направление сдвига: 0 — влево
 
#define LCD_FUNCTION         1<<5 /*Разрядность шины данных, кол-во строк, размер шрифта*/
#define LCD_FUNCTION_4BIT    0<<4 //Флаг, определяющий ширину шины данных: 0 — 4 разряда
#define LCD_FUNCTION_8BIT    1<<4 //Флаг, определяющий ширину шины данных: 1 — 8 разрядов
#define LCD_FUNCTION_1LINES  0<<3 //Режим развертки изображения на ЖКИ: 0 — одна строка
#define LCD_FUNCTION_2LINES  1<<3 //Режим развертки изображения на ЖКИ: 1 — две строки
#define LCD_FUNCTION_8DOTS   0<<2 //Размер матрицы символов: 0 — 5x8 точек
#define LCD_FUNCTION_10DOTS  1<<2 //Размер матрицы символов: 1 — 5x10 точек
 
#define LCD_SET_CGRAM        0x40 /*Присвоение счетчику курсора адреса в области CGRAM*/
 
#define LCD_SET_DDRAM        0x80 /*Присвоение счетчику курсора адреса в области DDRAM*/
 
/*Функция ожидания готовности контроллера hd44780. Можно считывать статусный бит,
но мы будем просто делать паузу, в течение которой команда будет гарантированно выполнена.*/
#define lcd_wait     delay_us(800);
 
/* Макрос перемещения курсора в начальную  позицию (0, 0) */
#define lcd_home      lcd_data(0x02, LCD_RS_COMMAND);
 
 
//========================= LCD Fuctions =========================
/* инициализация портов,
подключенных к жки
#define init_port\
    LCD_DATA_DDR = 0xF0;\
    LCD_DATA = 0x00;\
    LCD_CTRL_DDR = 0x03;\
    LCD_CTRL = 0x00;
*/
void Init_Port(void)
{
    LCD_DATA_DDR = 0xF0;
    LCD_DATA = 0x00;
    LCD_CTRL_DDR |= 0x07;
    LCD_CTRL = 0x00;
}
//========================= Init LCD =========================
#define e1 PORTC |= 0b00000010 // установка линии E в 1  эту строку ставишь рядом с инклудами
 
#define e0 PORTC &= ~0b00000010 // установка линии E в 0  эту строку ставишь рядом с инклудами
 
#define rs1 PORTC |= 0b00000001 // установка линии RS в 1 (данные)  эту строку ставишь рядом с инклудами
 
#define rs0 PORTC &= ~0b00000001 // установка линии RS в 0 (команда)  эту строку ставишь рядом с инклудами
 
 
 
 
 
void sendhalfbyte(unsigned char c)  //служебная функция для работы библиотеки
{
    c<<=4;
    c &= 0xF0;
    e1;
    PORTC &= 0b00001111;
    PORTC |= c;
    delay_ms(1);
    e0;
    delay_ms(1);
} 
 
void sendbyte(unsigned char c, unsigned char mode)  //служебная функция для работы библиотеки
{
    unsigned char hc=0;
    
    if(mode == 0)
      rs0;
    else
      rs1;
    delay_us(50);
    hc = c>>4;
 
    sendhalfbyte(hc);
    sendhalfbyte(c);
} 
 
void sendbuk(unsigned char c)     //функция отправки по одной букве, например: sendbuk('E');
{
    sendbyte(c,1);
}
 
void mesto(unsigned char x, unsigned char y) //функция для установки курсора, например: mesto(0,0); - установит 
{                                                        //курсор в начало дисплея
    char address;
    address = (64*y+x)|0b10000000;
    sendbyte(address, 0);
}
 
void sendsl(char str1[])  //функция отправки слова, например: sendsl('privet');
{
    unsigned char n;
    for(n = 0; str1[n] != 0; n++)
        sendbuk(str1[n]);
}
   
void Init_LCD(void)    //функция инициализации дисплея в 4 проводном режиме
{
    delay_ms(40); //Ждем 15 мс
 
    sendhalfbyte(0b00000011);
    delay_ms(1);
    sendhalfbyte(0b00000011);
    delay_ms(1);
    sendhalfbyte(0b00000011);
    delay_ms(1);
    sendhalfbyte(0b00000010);
    delay_ms(1);
    sendhalfbyte(0b00000010);
    delay_ms(1);
    sendhalfbyte(0b00000010);
    delay_ms(1);
    sendbyte(0b00101000, 0); //4бит-режим (DL=0) и 2 линии (N=1)
    delay_ms(1);
    sendbyte(0b00001100, 0); //включаем изображение на дисплее (D=1), курсоры никакие не включаем (C=0, B=0)
    delay_ms(1);
    sendbyte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
    delay_ms(1);
}
 
/* функция очистки дисплея и возврата
курсора в начальную позицию*/
void lcd_clear()
{
    sendbyte(0x01, LCD_RS_COMMAND);
    delay_us(1700);
}
 
 
 
 
 
 
 
 
//========================= Interrupts =========================
//функция обработчик прерывания по захвату
//Таймера 1
//Timer/Counter1 Capture Event
#pragma vector=12
__interrupt void Timer1_Capt(void)
{
    cli();
    
    if(First)
    {
      //f = Counter(2 байта) + ICR1(2 байта) - эта идея не оправдалась 
      f =  ICR1;
      First = 0;
      return;
    }   
    else
    {
      delta = ICR1;    
      delta -= f;
      f = 0;
      First = 0;
    }
    
    //расчет значения частоты
    freq = delta * 25.6;
    freq *= 1e-6;
    freq = 1/freq;    
    
    //f = (long int)((timer*F_CPU) / (timer2*256));
    //f = myicr;      //12345;
        
    //заполнение массива числом посимвольно
    itoa(freq, arr_f);
        
    //очистка дисплея ЖКИ
    lcd_clear();
        
    //курсор в 0-ю позицию первой строки
    //lcd_goto(0, 0);
    mesto(0, 0);
        
    //вывод значения на дисплей
    sendsl(arr_f);
    delay_ms(1000);    
        
        
    sei();    
    
}
 
//функция обработчик прерывания по переполнению Таймера 1
//Timer/Counter1 Overflow Event
#pragma vector=15
__interrupt void Timer1_Ovf(void)
{
    /*
    if(Counter == 65535)
    {
        Counter = 0;
        First = 1;
    }
    else
    {
        Counter++;
    }
    */
    f = 0;
    delta = 0;
    First = 1;
}
 
 
/*
//функция обработчик прерывания по внешнему запросу
#pragma vector=3
__interrupt void INT1_ISR(void)
{   
    //счет кол-ва импульсов
    timer++;
}
*/
 
 
 
 
 
//========================= Timers Init ========================= 
// Предварительная настройка таймера
void timer0_init()
{
    //Инициализация Т0
    //предделитель равен 32
    TCCR0 = (0 << CS02) | (1 << CS01) |  (1 << CS00);
    
    //настройка ножки OC0 в работу
    TCCR0 |= (0 << COM01) | (1 << COM00) | (1 << WGM01) | (0 << WGM00);
    
    //Выбор режима PWM и предделителя
    //устанавливаем период сигнала(для частоты 1кГц)
    OCR0 = 155;
    DDRB = (1 << 4);  //инициализация порта OC0 на выход
}
 
void timer1_init()
{
    //Инициализация T1
    TCCR1A = 0;
    //Внешний тактовый источник CLK = 10 Meg/256
    //No overflow
    //Input Capture
    TCCR1B = (1 << ICES1) | (1 << CS12) | (0 << CS11) |(0 << CS10);
    TCCR1C = 0;
    OCR1A = 2500;
    // Разрешаем прерывание по достижению максимума
    TIMSK  = (1 << TICIE1) | (1 << TOIE1);
    ETIMSK = 0x00;
    //Инициализация T1 на вход
    PORTD = 0;
    DDRD &= ~(1 << 4);
}
 
 
 
 
 
//========================= main ========================= 
void main(void)
{
    char Str[12] = {"Privet\0"};
    
    //Запрет прерываний
    cli();
    //инициализируем таймер
    timer0_init();
    timer1_init();
    
    /*
    //Настройка INT1
    EICRA = (1 << ISC11) | (1 << ISC10);
    EIMSK = (1 << INT1);
    */
    
    Init_Port();
    //инициализация ЖКИ
    Init_LCD();
    //очистить дисплей
    //lcd_clear();
    
    
    
    //функция передачи байта в жки */
    //void lcd_data(char c, char rs)
    //lcd_data('C', 1);
    
    sendsl(Str);  //Proverka
    
 
    mesto(0, 1);
    sendbuk('S');
    sendbuk('T');
    sendbuk('A');
    sendbuk('R');
    sendbuk('T');
    //mesto(0, 1);
    //sendsl("Proverka");
 
    // Глобальное разрешение прерываний
    sei();
    
    
    //Рабочий цикл
    while(1)
    {
    }
}

А, нет, смотри-ка, работает!!
Недооценил я AVR микроконтроллеры.
Даже на 1e-6 умножить может.
0
1122 / 482 / 205
Регистрация: 11.10.2018
Сообщений: 2,717
25.05.2020, 11:24 26
Вот что показывает.
0
Миниатюры
Частотомер на ATmega128  
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.05.2020, 11:24

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

частотомер
форумчани подскажите пожалуйста, разрабатываю вот этот частотомер...

частотомер на at89c51
Сделал модель частотомера ra4nalа в протеусе. &lt;Изображение удалено&gt; не могу разобраться,...

Сделал частотомер
Сделал частотомер на ATmega8 и EPM3064A. Всю информацию для повторения выложил здесь:...

Частотомер на Arduino
Плата Arduino Nano v3. Питание 5 в. Частота 16 М. Нужна помощь в написании программы для измерения...

Сбоит частотомер
Доброго времени суток! Проблема: считаю период входного прямоугольного импульса с помощью захвата...

Цифровой частотомер
Нужен совет опытных людей в схемотехнике. Задача следующая: необходимо разработать входную часть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
26
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.