Перейти к содержанию

crazz

Рекомендуемые сообщения

Вот щас в инете читаю как правильно делать и некоторые моменты не понимаю.

post-147349-0-48442600-1445116293_thumb.jpg

4. При возникновении прерывания:

вычитаем сохраненное время (t1) из захваченного значения времени (t2) и сохраняем результат периода Т;

сохраняем захваченное время t2.

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

Зачем мне чего то вычитать и тд? то время которое сохранилось мне и нужно, это то время которое прошло между импульсами. Зная его я могу посчитать скорость, или просто если это время меньше или равно 0.0147сек то значит скорость 100км в час.

Я может чего то не понимаю конечно.

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Таймер никто не обнуляет. Он - в свободном полёте считает от 0 до 65535, перебрасывается в 0 и снова до 65535. А модуль ССР на лету схватывает показания Таймера1 в момент фронта на входе ССР, записывает в свои регистры и вызывает прерывание. После этого неспеша в прерывании можно посмотреть, какое число таймера было захвачено, и вычесть предыдущий захват для получения разницы.

Это точное измерение, оно железно было записано от фронта сигнала. Потому что пока дойдёт дело до прерывания и анализа данных в обработчике, Таймер1 уже ускачет вперёд. Если опрашивать таймер в прерывании, то там хрен знает сколько микросекунд пройдёт от фронта до непосредственно чтения таймера.

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Пришёл второй импульс, защёлкнулось новое значение таймера 16260. В прерывании вычитаем старое из нового: 16260 - cnt0 = 14700, кладём cnt0=16260. Таким образом период между двумя импульсами скорости получился 14700 микросекунд, с точностью 1 мкс. И т.д.

Зачем так делать? почему нельзя в первом же прерывании сбросить таймер? И так каждый раз. и не надо ничего вычитать будет.

Ой одновременно написали.

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

Изменено пользователем Zombie47
Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Всё зависит от точности измерения.

В Вашем случае нужно измерить 14700 мкс. Если устраивает точность, типа, 20 мкс, то ваще можно поступить просто.

Забываем про ССР. Вешаем входные импульсы на вход внешнего прерывания RB0/INT. Тогда от фронта каждого импульса просто наступает прерывание. В обработчике прерывания останавливаем Timer1, читаем сколько получилось, сбрасываем в 0 и снова запускаем Timer1. Вот и всё.

Микросекундной точности не получить, а оно Вам и не надо.

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

Тут другое главное - быстро-быстро остановили, прочитали , обнулили и снова стартовали. На всё это, ну, потеряете десяток шагов в программе, 10мкс по времени, то есть измеренный период будет меньше на 10мкс чем фактический , ну, и плевать. Кстати, эти потерянные 10мкс можно потом просто добавить к результату, посчитать по шагам программы, сколько теряется и добавить. И ваще будет - красота!

Опять же, то ли дело ССР. Другие прерывания, кратковременные запреты, подсчёт потерянных шагов и всё такое - ни разу не проблема! ССР железно защёлкнул в нужное время и порядок. Как дойдут руки, программа посмотрит на результат ССР, задержки уже не важны.

Вобщем, выбирайте любой способ, оба подойдут.

Изменено пользователем Yurkin2015
Ссылка на комментарий
Поделиться на другие сайты

Если устраивает точность, типа, 20 мкс, то ваще можно поступить просто.

Посчитал при такой погрешности, погрешность скорости будет при 100км в час примерно 0.2 км в час. это конечно уже здорово. Мне нравится.

я впринципе изначально так и хотел сделать но проблема в том что вопервых таймер 0 не умеет работать с предделителем 1:1 а во вторых я не знаю как считать значение таймера.

Как я понимаю у таймера 1 это регистры TMR1H и TMR1L

А что делать если таймер переполниться?

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

Ну а далее пока машина разгоняется таймер на маленьких скоростях переполниться. что делать с таймером?

Ссылка на комментарий
Поделиться на другие сайты

К примеру мне нужно засечь время разгона до 100км в час

Я бы сделал так.

Импульсы скорости подаю на внешнее прерывание, RB0/INT.

Timer1 использовал для измерения периода импульсов скорости. Поставил предделитель на 8, тогда таймер 1 тикает каждые 8мкс. От каждого импульса скорости таймер 1 обнуляется. Значит, переполнение наступит при периоде 8*65536 мкс = 0.524288 сек, что соответствует скорости 2.8 км/час.

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

Timer0 использую для измерения времени разгона. Ставим предделитель 256, Timer0 переполняется каждые 256*256=65536 мкс. При этом вызывается третье прерывание. В этом прерывании от Timer0 просто увеличиваем переменную time на 1. Таким образом в time будет время разгона.

При старте, по нажатию кнопки присвамваем time=0 и запускаем оба таймера. От каждого импульса скорости измеряем период. Когда период стал меньше, чем 14700/8=1838 запоминаем значение time, умножаем time*65536, и получаем кол-во микросекунд разгона. При этом шаг измерения времени будет 0.065 сек.

Изменено пользователем Yurkin2015
Ссылка на комментарий
Поделиться на другие сайты

элементарно... 100км/час это определенный период импульсов, ожидаем его по INT , если все же произошло переполнение таймер1, тупо его выключаем (его значение мало и в условия проверки не попадает) ....

время считаем по таймер0 , тупо прибавляя в 32разрядную переменную 1<<8 ....

при совпадении периода с заданным значением считываем таймер0 и прибавляем его в 32разрядку = значение времени разгона в мкс при Fosc=4MHz

Ссылка на комментарий
Поделиться на другие сайты

При настройке регистра T1CON если 3 бит включить то почему то перестают работать порты на выход RB4, RB6, RB7, точнее перестают управляться. Ну об этом написано в даташите. Но поясните что это за генератор такой?

Я думал это типо источник тактирования таймера TMR1

T1CON = 0b00000000;
/*
7-6bit=0 (Read as 0)
5-4bit=00 (Предделитель для TMR1 1:1)
3bit=0 (T1OSCEN Внутренний генератор выкл 0 (если вкл то не будут работать RB6, RB7)
2bit=0 (Синхронизация внешнего тактового сигнала Если TMR1CS=0 то значение бита игнорируется)
1bit=0 (TMR1CS выбор источника тактового сигнала. 0 - внутренний генератор)
0bit=0 (TMR1ON 0 таймер выключен)

post-147349-0-30078100-1445130543.jpg

post-147349-0-34842100-1445130537_thumb.jpg

Ссылка на комментарий
Поделиться на другие сайты

Всетаки решил сначала разобраться с модулем CCP так как он мне пригодиться еще.

Что то делаю не так.

Вот у меня функция обработчик прерываний. Первое прерывание обрабатывается если поднят флаг CCP модулем. А он поднимает флаг по переднему фронту входного сигнала на порте RB2

Вот настройки CCP и TMR1

CCP1CON = 0b00000101;
/*
 7-6bit=0 (Read as 0)
 5bit=0 (Младшие биты скважности. В режиме захвата не используются)
 4bit=0 (Младшие биты скважности. В режиме захвата не используются)
 3-0bit=0101 (0101 - Захват по каждому переднему фронту сигнала)
*/
//Ниже настраиваем Таймер1 для модуля захвата, работают в паре.
   T1CON = 0b00000000;
/*
 7-6bit=0 (Read as 0)
 5-4bit=00 (Предделитель для TMR1 1:1)
 3bit=0 (T1OSCEN Внутренний генератор выкл 0 (еслди вкл то не будут работать RB6, RB7)
 2bit=0 (Синхронизация внешнего тактового сигнала Если TMR1CS=0 то значение бита игнорируется)
 1bit=0 (TMR1CS выбор источника тактового сигнала. 0 - внутренний генератор)
 0bit=0 (TMR1ON 0 таймер выключен)
*/

Ниже кусок программы по прерыванию.

void interrupt Timer (void)
{
 if (CCP1IF){//произошло прерывание по входному сигналу на RB2 с датчика скорости, по переднему фронту
 GIE = 0;// глобальный запрет прерываний
 current_timer = CCPR1L+(CCPR1H<<8);//время между двумя импульсами
 period = (unsigned int)(current_timer - old_timer);
 old_timer = current_timer;
 CCP1IF = 0;
 GIE = 1;// разрещаем прерывания
 }

 if (TMR1IF){//если таймер TMR1 переполнился
	 TMR1IF = 0;
 }

 if(TMR0IF) // таймер считает до такого числа которое мы указали в настройках таймера " OPTION_REG = 0b00000011; // настройки таймера 1:16 и установка Set timer TMR0 даташит page 54" и когда он досчитает он поднимает флаг, мол я досчитал! флаг TMR0IF если он равен 1 значит он поднят и выполняется тело ниже
	 {
			 TMR0IF=0; //сбрасывается этот же флаг чтобы он начал считать заново.
Ниже текст программы для динамической индикации.

На порт RB2 в протеусе я подаю импульсы длительностью 8.75 мс, ну или период 17.6мс

Так как новичок я делаю так:

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

У меня выводиться все хорошо.

Но если подставляю ей нужную функцию то не работает. выводит 0.

Далее я методом тыка подставляю ей различные регистры переменные и тд, и смотрю их значение. Но чето везде 0 =)))

Где ошибся?

Ссылка на комментарий
Поделиться на другие сайты

Но поясните что это за генератор такой?

Я думал это типо источник тактирования таймера TMR1

Да, так и есть. Это внешний аппаратный генератор для TMR1, обычно туда подключают кварц на 32768Гц и получают прерывания от таймера в 1 секунду. Либо можно подавать внешнюю частоту и таймер будет считать импульсы на выводе порта.

умножитель на 1000 :shok: это как????

Это довольно замороченная схема с простым принципом работы - как правило это схема PLL, такая же по принципу работы как во всех приёмниках с цифровой настройкой частоты - там берется опорная частота, например 500кГц и изменяется коэффициент умножения... в итоге получаем изменяемую цифрой частоту на выходе в диапазоне 76...108Мгц.

Изменено пользователем Alexeyslav

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

Всетаки решил сначала разобраться с модулем CCP так как он мне пригодиться еще.

Что то делаю не так.

Ниже кусок программы по прерыванию.

void interrupt Timer (void)
{

 GIE = 0;// глобальный запрет прерываний

 GIE = 1;// разрещаем прерывания

1. Почему Вы подаете сигнал на RB2, если вход захвата сидит на RB3?

Поставьте брекпойнт в обработчике и посмотрите что там происходит и по какому флагу.

2. В обработчике прерываний не нужно ни запрещать глобальное прерывание, ни разрешать . Это происходит АВТОМАТИЧЕСКИ при входе в обработчик и при выходе из него по ассемблерной инструкции retfie (она генерируется компилятором на выходе обработчика вместо инструкции return в конце обычной функции).

Имя инструкции retfie и означает return from interrupt with global interrupt enable.

(Флаги источников прерываний нужно проверять и затем сбрасывать).

ЗЫ. Я тут ранее несколько перестарался насчет типов переменных, меня чето переклинило на собственных задачах (я там измеряю опережение-отставание событий), поэтому можете все делать в unsigned int без приведения типов. Но все глобальные переменные, которые изменяются в прерывании обязаны иметь квалификатор volatile. Иначе компилятор может оптимизировать код в основном теле так, что переменная (особенно двух и более байтная) будет подразумеваться неизменной между двух операций, а существует вероятность ее изменения в прерывании, которое может произойти между этих двух операций. Возникнет трудно отлавливаемый баг...

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

Timer1 не забыли включить? У Вас T1CON = 0, то есть изначально таймер выключен. А если выключен, то всегда будет 0 на нём.

В начале программы надо разрешить прерывания GIE=1, т.к. они при старте программы по умолчанию выключены.

И потом, если таймер переполнился - он сам сбрасывается в 0, не надо его вручную сбрасывать в прерывании.

1. Почему Вы подаете сигнал на RB2, если вход захвата сидит на RB3?

Согласно дейташиту у этого пика два входа ССР1 - RB2 и RB3. Выбор конкретного входа определяется битом CCPMX в слове конфигурации ПИКа. Если CCPMX = 1, то вход ССР есть RB2. Поумолчанию в этом бите как раз единичка. Я так думаю.

Ссылка на комментарий
Поделиться на другие сайты

Timer1 не забыли включить? У Вас T1CON = 0, то есть изначально таймер выключен. А если выключен, то всегда будет 0 на нём.

Да я над этим думал. но вот у меня есть другая программа и там TMR0 используется для динамической индикации и все прекрасно работает, но я не могу найти в коде где он у меня включается=))))

В начале программы надо разрешить прерывания GIE=1, т.к. они при старте программы по умолчанию выключены.

Это да включено.

Я почему то посчитал, что речь о 628-м..

Да извиняюсь не указал PIC 16F819

Где то тут было сообщение про мою функцию прерывания.

Она у меня выглядит так void interrupt Timer (void)

и я на самом деле понятия не имею как надо, с ней все работает в другой программе =)

Вплане мне казалось что запись void interrupt уже изначально означает функцию обработчика прерываний а Timer это лишь название которое я придумал сам.

Ссылка на комментарий
Поделиться на другие сайты

Вплане мне казалось что запись void interrupt уже изначально означает функцию обработчика прерываний а Timer это лишь название которое я придумал сам.

Осталось только контроллеру сообщить для какого из прерываний этот обработчик... ведь там несколько векторов прерываний, а на какой вешать ваш обработчик, как компилятор узнает?

Изменено пользователем Alexeyslav

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

Осталось только контроллеру сообщить для какого из прерываний этот обработчик... ведь там несколько векторов прерываний, а на какой вешать ваш обработчик, как компилятор узнает?

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

Ссылка на комментарий
Поделиться на другие сайты

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

Так и есть, одно прерывание на всех. Алексей что-то перепутал.

Ссылка на комментарий
Поделиться на другие сайты

Прописал в инициализации T1CON = 0b00000001;

Но чето не хочет работать =) понятное дело где то ошибка у меня. Значение регистров вывожу на дисплей вижу какие то циферки мелькают.

CCPR1L, CCPR1H

Но медленно мелькают.

Так же если вывожу значение current_timer

тоже мелькают циферки.

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

Ссылка на комментарий
Поделиться на другие сайты

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

/*
* File: newmain.c
* Author: Vlad
*
* Created on 16 ???????? 2015 ?., 0:37

/*
7bit=0 ()
6bit=0 ()
5bit=0 ()
4bit=0 ()
3bit=0 ()
2bit=0 ()
1bit=0 ()
0bit=0 ()
*/
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF	 // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON	 // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF	 // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = ON	 // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF	 // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF	 // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF	 // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB2	 // CCP1 Pin Selection bit (CCP1 function on RB2)
#pragma config CP = OFF		 // Flash Program Memory Code Protection bit (Code protection off)
#include <xc.h>
#include <pic.h>
#include <pic16f819.h>
#include <stdlib.h>
#define dig1 RA3 //индикатор 1
#define dig2 RA2 //индикатор 2
#define dig3 RA7 //индикатор 3
#define LED PORTB
// глобальные переменные
volatile unsigned int period;
long old_timer;
long current_timer;
long speed;
const unsigned char digits [23] = {0x44,0x7D,0x16,0x15,0x2D,0x85,0x84,0x5D,0x04,0x05,0xFF,0x86,0x0C,0x40,0x79,0x12,0x11,0x29,0x81,0x80,0x59,0x00,0x01}; //0,1,2,3,4,5,6,7,8,9,пусто, E,R, - // это коды которые сообщают какие светодиоды поджечь в индикаторе чтобы отобразить ту или иную цифру или символ. Код зависит от того какая нога к какому выводу МК подрублена. в инете есть калькуляторы.
					 unsigned int i				 ; //
volatile		 unsigned char a,b					 ;//volatile это спецификатор говорит компилятору, что это переменная, чтобы он ее не оптимизировал, Отдельная плюшка)
volatile		 unsigned char LEDS[3]		 ; //

//***********************************************************************
//* ИНИЦИАЛИЗАЦИЯ МК
//***********************************************************************
void init(void)
{
INTCON =0b00000000; // даташит page 18 ниже описание:
//7bit=0 (GIE глобальное разрешение прерываний выкл)
//6bit=0 (PEIE разрешение прерываний от периферийных модулей выкл)
//5bit=0 (TMR0IE разрешение прерывания по переполнению таймера TMR0 выкл)
//4bit=0 (INTE разрешение внешних прерываний выкл)
//3bit=0 (RBIE разрешение прерывания по изменению сигнала на входах RB4-RB7)
//2bit=0 (TMR0IF флаг прерывания который поднимается при переполнении таймера, мы его сбрасываем в 0)
//1bit=0 (INTF флаг прерывания который поднимается если выполнено условие внешнего прерывания на выводе RB0/INT, мы его сбрасываем в 0)
//0bit=0 (RBIF флаг прерывания который поднимается при измении сигнала на одном из входов RB4-RB7, мы его сбрасываем в 0 )
OSCCON = 0b01100100; //даташит page 38 ниже описание:
//7bit=0 (READ as 0)
//6-4bit=110 (частота внутреннего генератора 4mhz)
//3bit=0 (READ as 0)
//2bit=1 (IOFS стабилизация частоты INTOSC вкл )
//1-0bit=0 (READ as 0)
 // ниже настройка портов
PORTA = 0; //обнуляем порты а
PORTB = 0;
TRISA = 0b01110001; //порты RA2, RA3, RA7, RA1 на выход а остальные на вход
TRISB = 0b00000100; // RB2 на вход для модуля захвата CCP
PORTA = 0; //обнуляем порты а
PORTB = 0;
// ниже настройка АЦП
ADCON0=0b01000000; //даташит page 81 ниже описание:
//7-6bit=01 (Если ADCS2=0 то задается частота Fosc/8)
//5-3bit=000 (канал для АЦП RA0)
//2bit=0 (GO/DONE как я понял это что вроде флага, в процессе АЦП или нет )
//1bit=0 (READ as 0)
//0bit=1 (ADON этот бит запускает работу ацп.)

// ниже настройка таймера TMR0
TMR0 = 0; //сбрасываем таймер в 0
TMR1 = 0;
OPTION_REG = 0b00000011; //ниже описание (даташит page 54):
//7bit=0 (portb подтягивающие резисторы вкл)
//6bit=0 (INTEDG прерывания по заднему фронту сигнала)
//5bit=0 (источник тактирования таймера 0 = внутренний генератор)
//4bit=0 (в какую сторону считает таймер, от меньшего к большему)
//3bit=0 (прескалер применяется к Timer0 а не к WDT)
//2-0bit=011 (прескайлер равен 1:16)
 //Ниже настраиваем модуль захвата
CCP1CON = 0b00000101;
/*
7-6bit=0 (Read as 0)
5bit=0 (Младшие биты скважности. В режиме захвата не используются)
4bit=0 (Младшие биты скважности. В режиме захвата не используются)
3-0bit=0101 (0101 - Захват по каждому переднему фронту сигнала)
*/
//Ниже настраиваем Таймер1 для модуля захвата, работают в паре.
T1CON = 0b00000001;
/*
7-6bit=0 (Read as 0)
5-4bit=00 (Предделитель для TMR1 1:1)
3bit=0 (T1OSCEN Внутренний генератор выкл 0 (еслди вкл то не будут работать RB6, RB7)
2bit=0 (Синхронизация внешнего тактового сигнала Если TMR1CS=0 то значение бита игнорируется)
1bit=0 (TMR1CS выбор источника тактового сигнала. 0 - внутренний генератор)
0bit=1 (TMR1ON 1 таймер включен)
*/

// ниже разрешение прерываний
TMR0IE = 1; //разрешение прерывания по таймеру0
GIE = 1; // глобальное разрешение прерываний
};

void interrupt Timer (void)
{
 if (CCP1IF){//произошло прерывание по входному сигналу на RB2 с датчика скорости, по переднему фронту
 current_timer = CCPR1L+(CCPR1H<<8);//время между двумя импульсами
 period = (current_timer - old_timer);
 old_timer = current_timer;
 CCP1IF = 0;
 }

 if (TMR1IF){//если таймер TMR1 переполнился
	 TMR1IF = 0;
 }

 if(TMR0IF) // таймер считает до такого числа которое мы указали в настройках таймера " OPTION_REG = 0b00000011; // настройки таймера 1:16 и установка Set timer TMR0 даташит page 54" и когда он досчитает он поднимает флаг, мол я досчитал! флаг TMR0IF если он равен 1 значит он поднят и выполняется тело ниже
	 {
			 TMR0IF=0; //сбрасывается этот же флаг чтобы он начал считать заново.
			 dig1=0; NOP(); dig2=0;NOP(); dig3=0; LED=(digits [10]); // гасим все разряды
			 b++; //увеличиваем b на 1. изначально она равна нулю.
			 if (b>130){b=0;} //если b уже равна больше 130 то обнуляем её. Это как бы второй счетчик, параллельный основному.
			 a++; //тоже что и b но счетчик для индикации
			 switch(a) //выбор вариантов в зависимости от значения а. В первый раз а будет равно 1 и поэтому будет работать case 1
	 {	 // Динамическая индикация.
					 case 1: LED=(LEDS[2]); dig1=0; NOP(); dig2=0; NOP(); dig3=1; break; // сначала отправляем цифру LEDS[2] а потом поджигаем первый разряд dig3=1 чтобы увидеть эту цифру
					 case 2: LED=(LEDS[1]); dig1=0; NOP(); dig3=0; NOP(); dig2=1; break; // второй разряд
					 case 3: LED=(LEDS[0]); dig2=0; NOP(); dig3=0; NOP(); dig1=1; a=0; break; // третий разряд и вконце обнуляем a и счетчик теперь опять будет считать с 0
	 }
}
}
int Speed (int tm){ //функция формула расчета скорости
			 tm = (2.032/((period/1000000)*5))*3.6;
}
void convert (void)//функция которая переводит значения температуры в графические показания на 3 разрядном семисегментном индикаторе
{
unsigned int d1_1; //
int tm;
unsigned char tempLEDS[3]			 ; // масив в который будем заносить значения из другого массива (не числа)
tm = current_timer; //вывод на индикатор данного числа

	 if(tm>=0 && tm<10){ //если tm больше 0 но меньше 10 то выполняем тело
			 tempLEDS[2]=digits [10]; //посылаем пустой знак
			 NOP();
			 tempLEDS[1]=digits [10]; //посылаем пустой знак
			 NOP();
			 tempLEDS[0]=digits [tm]; //посылаем знак равный tm
	 }
	 if (tm >= 10 && tm <= 99){
			 tempLEDS[2]=digits [10]; // если значение от 10 до 99 то на 1 индикатор подаем цифру пусто.
			 NOP();
			 d1_1=tm%100;
			 tempLEDS[1]=digits [d1_1/10];						 // Получаем разряд
			 tempLEDS[0]=digits [d1_1%10];				 // Получаем разряд

	 }
	 if (tm >=100 && tm < 999 ){// аналогично но для значений от 100 до 999
			 d1_1=tm%100;
			 tempLEDS[2]=digits [tm/100];// Получаем разряд
			 tempLEDS[1]=digits [d1_1/10]; // Получаем разряд
			 tempLEDS[0]=digits [d1_1%10]; // Получаем разряд
	 }
GIE = 0;// глобальный запрет прерываний чтобы три переменных ниже записались и запись не прервалась каким нить прерыванием случайно.
// ниже по сути идет описания массива LEDS чему равны его ячейки
	 LEDS[0]= tempLEDS[2]; // значению массива LEDS с индексом 0 присваиваем значение массива tempLEDS с индексом 2, если почитать выше то будет видно что мы присваиваем посчитанные значения разрядов.
	 LEDS[1]= tempLEDS[1];
	 LEDS[2]= tempLEDS[0];
GIE = 1;// врубаем прерывания заново.
}

//***********************************************************************
//* ОСНОВНАЯ ПРОГРАММА
//***********************************************************************
void main (void)
{
 init(); //вызывается функция init
 for(i=255;i>0;i--); //небольшая пауза
	 //******** ГЛАВНЫЙ ЦИКЛ *****************
 while (1) //бесконечный цикл
	 {
	 convert (); //в котором вызывается функция convert, ищим её выше и смотрим что в ней происходит и какие в ней функции вызываются.
	 };
}

Ссылка на комментарий
Поделиться на другие сайты

Бит PEIE в регистре INTCON выключен, значит прерывания от ССР не пройдут.

Бит CCP1IE в регистре PIE1 тоже надо поставить в 1, иначе прерывания от ССР не пройдут.

Выводите на индикатор period, а то current_timer всё время будет изменяться и мелькать на индикаторе.

Кстати, о выводе. У Вас значение периода в микросекундах, величина периода будет единицы-десятки тысяч. На трёх разрядах индикатора увидите только последние 3 цифры, они могут болтаться от нестабильности генератора, например.

Изменено пользователем Yurkin2015
Ссылка на комментарий
Поделиться на другие сайты

Бит PEIE в регистре INTCON выключен, значит прерывания от ССР не пройдут.

А блин точно забыл посмотреть прерывания =)) PEIE не нужен же для TMR0 поэтому и вырублен был в предыдущей проге.

Ну и CCP1IE соответственно тоже забыл что надо врубить.

ыводите на индикатор period, а то current_timer всё время будет изменяться и мелькать на индикаторе.

Вообще туда будет выводиться функция

Speed (tm)

Все включил но все ровно если вывожу period То просто ноль выводит

post-147349-0-99599200-1445213670_thumb.jpg

У Вас значение периода в микросекундах, величина периода будет единицы-десятки тысяч. На трёх разрядах индикатора увидите только последние 3 цифры, они могут болтаться от нестабильности генератора, например.

Значение периода да у меня в микросекундах, подаю 19,5 мсек тоесть 19500 микросек, тоесть я должен увидеть хотя бы 500, а я вижу 0

Изменено пользователем Zombie47
Ссылка на комментарий
Поделиться на другие сайты

Уважаемый. А давайте Вы перепишете весь код.

Там просто нечего анализировать. ВСЕ не так.

Принципы построения.

В прерывании программа должна находиться как выстрел - мгновение. Все должно выполняться в main по флагам (не по флагам прерываний, а по ВАШИМ программным флагам, которые устанавливаются в прерывании.

То есть заведите в своей программе в разделе объявления переменных СТРУКТУРУ вида:

struct flags {
unsigned <имя флага 1>: 1;
unsigned <имя флага 2>: 1;
unsigned <имя флага 3>: 1;
//.......................
//столько - сколько нужно
unsigned <имя флага N>: 1;
} flagsbits;

Обращение к элементам структуры (в данном случае они однобитные)

// сбросить флаг
flagsbits.<имя флагаN> = 0;
// установить флаг
flagsbits.<имя флагаN> = 1;
// если флаг установлен
if (flagsbits.<имя флагаN>)
{
}
// если флаг сброшен
if (! flagsbits.<имя флагаN>)
{
}
//
если одновременно установлено два флага
if (flagsbits.<имя флагаN> && flagsbits.<имя флагаK>)
{
}
// если установлен один или два флага
if (flagsbits.<имя флагаN> || flagsbits.<имя флагаK>)
{
}

В прерывании эти флаги взводят как требование их исполнить в main, а при исполнении в main их сбрасывают.

В прерывании снимают данные с регистров CCPR, TMR, ADRES и прочих, максимум вычисляют простые (максимум unsigned int) суммы - разности и тут же выходят. Всякие расчеты вывода, сам вывод на индикаторы , деления-умножения и прочую долгоиграющую лабуду - ВСЕ В ГЛАВНЫЙ ЦИКЛ.

Не нужно при выводе запрещать прерывания. У Вас вообще это делается в прерывании, что при запрете бессмысленно, ибо и так запрещены, а при разрешении приводит к вложенным вызовам, что разрушает сохраненный компилятором контекст и ПОЛНОСТЬЮ РАЗРУШАЕТ АЛГОРИТМ.

Прерывание не может разрушить переменные, которые оно не модифицирует в своем теле. Если Вы объявите переменную как volatile, компилятор никогда не будет пользоваться такой переменной для вычисления непосредственно, а создаст ее копию ОДНОЙ ИНСТРУКЦИЕЙ, либо сам запретит прерывания на время создания копии. То есть все глобальные переменные которые модифицируются в прерывании нужно объявлять с квалификатором volatile.

Еще раз. Не обижайтесь. Написана полная чушь. Исправлять бессмысленно.

И еще. При работе с симулятором не нужно ничего выводить на индикацию. Все можно посмотреть в Watch в режиме отладки. Поставили точку останова в нужном месте - посмотрели что в переменных. Если нужно прошли по шагам.

Это в железе в этом контроллере нет блока отладки (дебаггера), а в модели симулятора все можно дебажить (отлаживать).

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

подаю 19,5 мсек тоесть 19500 микросек, тоесть я должен увидеть хотя бы 500, а я вижу 0

Вот, в программе convert, если tm>999, то оно не попадает в условия и не происходит разложение на сотни-десятки-единицы. При этом в LED[0], LED[1], LED[2] просто записывается какой-то мусор. А у Вас как раз 19500 > 999.

Поставьте ещё условие, мол, если tm>999, то tm=999. И все большие значения будут отображаться как "999", например.

Или сначала отсеките тысячи tm=tm%1000, оставьте от числа только младшую часть, потом уже преобразуйте. Тогда увидите "500" от "19500".

Вот ещё одна неувязка - вычисление скорости:

tm = (2.032/((period/1000000)*5))*3.6;

У Вас величина периода меньше миллиона, поэтому первое деление period/1000000 даст результат меньше 1, а в целых числах это просто ноль.

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

tm = 1463040/period;

Вот это уже гораздо лучше выглядит. Вот так я бы использовал в программе для вычисления скорости. Лучше потому, что нет дробных переменных, а просто целочисленное деление. И выполняется быстрее процессором и памяти меньше жрёт.

Изменено пользователем Yurkin2015
Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...