реклама на сайте
подробности

 
 
> Первый проект на АТМЕГА
ddwrt
сообщение Apr 18 2016, 09:19
Сообщение #1





Группа: Участник
Сообщений: 6
Регистрация: 18-04-16
Пользователь №: 91 345



Есть задача - в зависимости от скорости,оборотов и температуры двигателя, открывать клапан.
Температура - аналоговый сигнал, примерно от 4 до 1 вольт.
Обороты - импульсы, причем длинна импульса означает время, потраченное на работу одного цилиндра за полный оборот двигателя.
Скорость - 9 импульсов за полный оборот колеса.
Условие срабатывания клапана - температура более 50 гр. (~2.5 вольт), обороты более 1200 либо скорость более 60 км/ч.

Написал код (до этого с программированием не связывался практически совсем):

CODE
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned int spd_impulse = 0;
volatile unsigned int spd = 0;
volatile unsigned int rpm = 65535;
volatile unsigned int temp_flag = 0;
ISR(INT0_vect) {
spd_impulse++; // Считаем импульсы с датчика скорости
}
ISR(TIMER2_COMP_vect) {
spd = spd_impulse; // Передаем переменной spd колличество импульсов за 0.2 сек
spd_impulse = 0; // обнуляем счетчик
}
ISR(TIMER1_CAPT_vect) {
if((TCCR1B & (1<<ICES1)) != 0 ) {
TCNT1 = 0;
ICR1 = 0;
TCCR1B &= ~(1<<ICES1); // Прерывание по нисходящему фронту
}
else {
TCCR1B |= (1<<ICES1); // Прерывание по восходящему фронту
rpm = (ICR1); // Передаем переменной rpm количество тиков счетчика, поместившихся в длину импульса от тахометра
}
}
ISR(ADC_vect){
temp_flag = ADC; // Присваиваем переменной значение ЦАП
ADCSRA |=(1<<ADSC); // Запускаем ЦАП
}
int main(void)
{
sei();

// настройка прерываний по импульсам с датчика скорости
GICR |= (1 << INT0);
MCUCR |= (1 << ISC01)|(1 << ISC00); // Прерывание формируется по переднему фронту

// Настройка таймера для подсчета количества импульсов скорости каждые 0.2 сек
OCR2 = 0xC4; // Отчитываем 0.2 секунды.
TIMSK |= (1<<OCIE2); // Прерывание по совпадению
TCCR2 |= 0x07; // делитель на 1024
TCCR2 |= (1<<WGM21); // Сброс при совпадении

// Настройка прерываний и таймера тахометр
TIMSK |= (1<<TICIE1); // разрешить прерывание на захват
TCCR1B |= (1<<ICES1); // Прерывание по восходящему фронту
TCCR1B |= (1<<CS10)|(1<<CS11); // тактирование счетчика 64
// Датчик температуры
ADCSRA |=(1<<ADEN)|(1<<ADIE)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);
ADMUX |=(1<<REFS0)|(1<<REFS1)|(0<<MUX0)|(0<<MUX1)|(0<<MUX2)|(0<<MUX3);
ADCSRA |=(1<<ADSC); // Запускаем ЦАП

DDRC &= ~(1<<0); // Порт датчика температуры
DDRD |= (1<<0); // Порт включения клапана
DDRB |= (1<<1); // Индикация температура
DDRB |= (1<<2); // Индикация обороты
DDRB |= (1<<3); // Индикация скорость

volatile unsigned char rpm_flag = 0;
volatile unsigned char spd_flag = 0;
while(1) {
// Задаем люфт условий открывания клапана
if (rpm < 130) {
rpm_flag = 1;
}
else if (rpm > 135) {
rpm_flag = 0;
}
if (spd > 11) {
spd_flag = 1;
}
else if (spd < 10) {
spd_flag = 0;
}
// Проверяем условия
if (temp_flag < 1000) { // Ждем пока температура достигнет рабочей
ADCSRA &= ~(1<<ADSC)|(1<<ADIE); // Отключаем работу АЦП до следующего холодного старта
PORTB |= (1<<1); // Сигнализируем, что температура в норме

if (spd_flag == 1) { // Проверка флага скорости
PORTD |= (1<<0); // Открываем клапан
PORTB |= (1<<3); // Сигнализируем открытие клапана по скорости
}
else if (rpm_flag == 1 ) { // // Проверка флага оборотов
PORTD |= (1<<0); // Открываем клапан
PORTB |= (1<<2); // Сигнализируем открытие клапана по оборотам
}
else {
PORTD &= ~(1<<0); // Отключаем клапан
}
}
PORTB &= ~(1<<1)||(1<<2)|(1<<3); // Гасим всю индикацию.
}
}

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

Сообщение отредактировал Herz - Apr 20 2016, 08:11
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
SlavaV
сообщение Apr 19 2016, 13:19
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 100
Регистрация: 13-06-06
Из: г.Улан-Удэ
Пользователь №: 18 024



Зачем задействовать прерывание INT0 не проще на счётчик подать (пусть сам считает)
Go to the top of the page
 
+Quote Post
ddwrt
сообщение Apr 20 2016, 04:47
Сообщение #3





Группа: Участник
Сообщений: 6
Регистрация: 18-04-16
Пользователь №: 91 345



Цитата(SlavaV @ Apr 19 2016, 14:19) *
Зачем задействовать прерывание INT0 не проще на счётчик подать (пусть сам считает)

Мне нужно знать время между импульсами, чтобы посмотреть скорость. Если подать на счетчик, он мне просто посчитает импульсы, дальше что с ними делать? Запускать еще один таймер, чтобы узнать за какое время первый таймер насчитал импульсы?

Сообщение отредактировал ddwrt - Apr 20 2016, 04:49
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 20 2016, 05:42
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(ddwrt @ Apr 20 2016, 10:47) *
Мне нужно знать время между импульсами, чтобы посмотреть скорость. Если подать на счетчик, он мне просто посчитает импульсы, дальше что с ними делать? Запускать еще один таймер, чтобы узнать за какое время первый таймер насчитал импульсы?

Для измерения интервалов между импульсами гораздо лучше использовать таймер, а не прерывания. В LPC17xx, например, для этого имеется опция CAPTURE в его таймерах - позволяет защёлкивать значение счётчика таймера по внешнему сигналу (с одновременным прерыванием). Я думаю и в других МК есть похожая возможность.
А почему лучше через таймер - подумайте сами.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 29th August 2025 - 21:03
Рейтинг@Mail.ru


Страница сгенерированна за 0.01368 секунд с 7
ELECTRONIX ©2004-2016