»Радиолюбитель>PIC контроллеры. Программаторы и первый проект на PIC
petrd 10:41 20.07.2018
Сообщение от leobor:
Доброго дня всем. Время от времени начинаешь понимать, что надо когда то начинать осваивать, но постоянно находятся причины отложить.
По делу - назрела необходимость сконструировать простое устройство, но время не будет ждать, пока я сам лично научусь. Нужно адаптировать энкодер (валкодер). Попробовал на дискретных элементах - как минимум 3 корпуса и тяжеловатая трассировка. Есть у меня 12F683 - думаю, на нем это получилось бы гораздо проще. Есть прогер - так что и с программированием проблем не будет. Нет самого "малого" - прошивки. Может кто помочь написать? Вернее, просто написать (ибо сам я даже не знаю с чего начинать, а времени научиться сейчас попросту нет)...
Опишите подробнее задачу или здесь, а хотите в личку.
[Ответ]
Goha 21:46 05.02.2019
Здравствуйте. Изготовил кабелеискатель. http://vrtp.ru/index.php?showtopic=13470&st=90 Передатчик собран по представленной схеме. Частота на выходе 125 кГц с АМ модуляцией 1 Гц. Использую кварц 16 МГц, контроллер PIC12f675.
Появилась хотелка иметь на выходе двухтональный сигнал. 125 кГц скажем 4 раза в секунду поочередно модулируется 1 кГц затем 2 кГц и т. д. Короче хочу чтоб было в линии «ти-ли-ти-ли-ти… » . Решил переписать прошивку самостоятельно в среде mikroC PRO for PIC используя прерывание Timer0. По прерыванию инвертирую сигнал на ножке . Предделитель таймера рассчитал калькулятором PICTimerCalculator. По расчетам, на 6 ноге должно быть 125 кГц (несущая) а частотомер (в железе) показывает не более 16 кГц. В программе модуляцию не использую, пока не разберусь с несущей. С контролером имею дело впервые. Пытаюсь разобраться, но чувствую, что самостоятельно не справлюсь. Может контроллеру просто не хватает скорости?
Прошу вашей помощи.
Код:
/* pic12F675 внешний кварц 16 Мгц
выход 6 нога GP1
генерация 1кгц и 2 кгц меняется с частотой 4 гц. несущая 125 кгц.
1000гц = 125000/125 2500гц = 125000/50 5гц = 125000/25000
//Timer0
//Prescaler 1:1; TMR0 Preload = 240; Actual Interrupt Time : 4 us
*/
unsigned int T5; // переменная счетчик для 4 Гц 0 .. 65535
bit kvant, Maska, F5; //переменная
void InitTimer0(){
CMCON = 0x07; // Disable Comparator
ADCON0 = 0x00; // Disable ADC
ANSEL = 0x00; // All ports in digital
TRISIO = 0x00; // All pins in OUT
GPIO = 0; // на выводах gp 0
//OPTION_REG = 0xA8; // Assign prescaler to TMR0
//Timer0 Registers:
//Prescaler=1:1; TMR0 Preset=240; Freq=125*000,00Hz; Period = 4 ns
WPU = 0x00; //Выключение подтягивающих резисторов
OPTION_REG.NOT_GPPU = 1; // bit 7 Запретить использование подтягивающих резисторов 1, разрешить 0.
OPTION_REG.INTEDG = 0; // bit 6 Выбор фронта импульса на входе внешнего прерывания.
OPTION_REG.T0CS = 0; // bit 5 выбор тактового сигнала 1 внешний gp2 0 внутренний генератор или кварц.
OPTION_REG.T0SE = 0; // bit 4 TMR0 выбор фронта приращения при внешнем тактовом сигнале bit: 0=low/high / 1=high/low
OPTION_REG.PSA = 0; // bit 3 выбор включения предделителя bit: 1 перед WDT, 0 перед Tmr0
OPTION_REG.PS2 = 0; // bits 2-0 PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0;
OPTION_REG.PS0 = 0;
TMR0 = 240; //240 устанавливаем начальное значение Timer0 250 кГц
// один период два переключения порта
//INTCON = 0xA0; // Enable TMRO interrupt
INTCON.T0IE=1; // разрешили прерывания по переполнению TMR0
INTCON.GIE=1; // включили механизм прерываний
kvant = 0; // переменная генератор 125 кГц ее выводим на 6 ногу
Maska = 0; //переменная состояние выхода модуляция частотами
F5 = 0; //переменная переключатель частоты 1кГц 2кГц
T5 = 0; //переменная счетчик для 4 Гц
}
void Interrupt(){
if (INTCON.T0IF){ // флаг прерывания переполнения Timer0 поднялся
kvant = ~kvant; // инвертируем состояние переменной после прерывания
//kvant = kvant&Maska; // применим маску разрешающую изменять состояние для выхода(логическое И)
GPIO.B1 = kvant; // Выводим сигнал на 6 ногу
//T5++; // increment T5
//if (T5 > 25000){ // задержка для 4 Гц
// T5 = 0;
// F5 = ~F5; // Инвертируем флаг изменения частоты 1кГц 2кГц
// }
INTCON.T0IF = 0; // сбрасываем флаг прерывания Timer0
INTCON.T0IE = 1; // разрешили прерывания по переполнению TMR0
TMR0 = TMR0 + 240; // устанавливаем начальное значение Timer0
}
}
void main() {
InitTimer0();
do{
// if (F5) {
//Delay_us(500);
//}
//else{
//Delay_ms(1);
//}
//Maska = ~Maska;
} while(1);
}
Пробовал и так TMR0 = 240;
Работает, да частота не та.
Автор статьи писал прошивку на ассемблере. Вот я и думаю, может контроллеру не хватает скорости для обработки прерывания написанного на Си.
[Ответ]
petrd 09:36 06.02.2019
Сообщение от Goha:
Пробовал и так TMR0 = 240;
Работает, да частота не та.
Автор статьи писал прошивку на ассемблере. Вот я и думаю, может контроллеру не хватает скорости для обработки прерывания написанного на Си.
Возможно. Уберите все из прерывания до минимума, добейтесь какой-то частоты на выходе которая совпадает с расчетами и измерениями и начните ее повышать, посмотрите когда перестанет расти. А потом добавляйте код в прерывание и тоже смотрите. Все будет понятно.
[Ответ]
Стр@нник 19:58 06.02.2019
Goha, при написании программ на С их объём в памяти и оптимизация, а соответственно и скорость обработки, здорово зависят от компилятора. С PIC не работал, на Атмегах ощутил.
[Ответ]
Стр@нник 06:21 07.02.2019
Прерывания таймера по достижению значения в PIC нет? Зачем использовать прерывание по переполнению?
[Ответ]
petrd 06:42 07.02.2019
Сообщение от Стр@нник:
Прерывания таймера по достижению значения в PIC нет?
petrd, предполагаю что загвоздка в описании прерывания. Я написал бы так: после наступления прерывания таймер остановить, прерывания запретить, сброс флага и обнуление счётчика таймера, требуемая процедура, запись нужного значения в счётчик, пуск таймера, разрешение прерываний. На мой взгляд предоставленном коде происходит следующее: при возникновении прерывания и его выполнения счётчик таймера продолжает считать. В момент установки начального значения происходит суммирование значения в регистре с заданным числом. Соответственно следующее прерывание наступит раньше и погрешность эта растёт с каждым циклом. На крайняк добавить строку в программу, обнуляющую счётчик таймера. Что думаете?
[Ответ]
Goha 23:16 07.02.2019
Ребята, спасибо за поддержку. Походу сам запутался и вас начал путать.
Естественно я пробовал разные варианты конфигурации с делителем и проверял в железе. Но всегда писал так
Код:
OPTION_REG.PSA = 1; // bit 3 выбор включения предделителя bit: 1 перед WDT, 0 перед Tmr0
Это значит, что предделитель был переключен на сторожевой таймер, а я получал «среднюю температуру на марсе» вместо временных промежутков.
На форум по ошибке выложил последнюю версию, где
Код:
OPTION_REG.PSA = 0;
этот вариант я то и не проверял. Извините за то, что ввел вас в заблуждение. Возможно, что код, который я выложил работоспособен. На выходных проверю в железе.
Спросите почему ставил 1? Потому что учился, повторял по примеру (с ошибкой) https://alex-exe.ru/radio/microcontrollers/timer-pic/[Ответ]
Goha 21:39 18.02.2019
«Слабенький» этот контроллер для таких частот, но я получил, что хотел. Может, кому пригодится. Короче, сделал наоборот. В основном цикле формирую несущую, а в прерывании управляю модуляцией сигнала. Кварц заменен на 20Мгц.
Код:
/* pic12F675 pic12F629 внешний кварц 20 Мгц
выход 6 нога GP1
генерация приблизительно 1кгц и 2 кгц меняется с частотой 4 гц.
несущая 125 кгц.
*/
unsigned int T5; // переменная счетчик для 4 Гц 0 .. 65535
bit kvant, Maska, F5; //переменная
void InitTimer0(){
CMCON = 0x07; // Disable Comparator
//ADCON0 = 0x00; // Disable ADC
//ANSEL = 0x00; // All ports in digital
TRISIO = 0x00; // All pins in OUT
GPIO = 0; // на выводах gp 0
WPU = 0x00; //Выключение подтягивающих резисторов
OPTION_REG.NOT_GPPU = 1; // bit 7 Запретить использование подтягивающих резисторов 1, разрешить 0.
OPTION_REG.INTEDG = 0; // bit 6 Выбор фронта импульса на входе внешнего прерывания.
OPTION_REG.T0CS = 0; // bit 5 выбор тактового сигнала 1 внешний gp2 0 внутренний генератор или кварц.
OPTION_REG.T0SE = 0; // bit 4 TMR0 выбор фронта приращения при внешнем тактовом сигнале bit: 0=low/high / 1=high/low
OPTION_REG.PSA = 0; // bit 3 выбор включения предделителя bit: 1 перед WDT, 0 перед Tmr0
OPTION_REG.PS2 = 0; // bits 2-0 PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0;
OPTION_REG.PS0 = 1;
TMR0 = 1; // устанавливаем начальное значение Timer0
INTCON.T0IE = 1; // разрешили прерывания по переполнению TMR0
INTCON.GIE = 1; // включили механизм прерываний
kvant = 0; // переменная генератор 125 кГц ее выводим на 6 ногу
F5 = 0; //переменная переключатель частоты 1кГц 2кГц
T5 = 0; //переменная счетчик для 4 Гц
Maska = 1; //переменная состояние выхода модуляция частотами
}
void Interrupt(){
if (INTCON.T0IF){ // флаг прерывания переполнения Timer0 поднялся
TMR0 = 1; // устанавливаем начальное значение Timer0
T5++; // increment T5
if (T5 > 1000){ // задержка для ~4 Гц
T5 = 0;
F5 = ~F5; // Инвертируем флаг изменения частоты ~1кГц ~2кГц
}
if (F5) {
OPTION_REG = 0x10000001;
}
else{
OPTION_REG = 0x10000010;;
}
Maska = ~Maska;
INTCON.T0IF = 0; // сбрасываем флаг прерывания Timer0
}
}
void main() {
InitTimer0();
do{
asm {
nop // подобрал 125 кгц, без вставки nop 178,5 кгц
nop
nop
nop
nop
nop
}
kvant = ~kvant; // инвертируем состояние переменной
kvant = kvant&Maska; // маской модулируем несущую(логическое И)
GPIO.B1 = kvant; // Выводим сигнал на 6 ногу
} while(1);
}
Хочу выразить огромную благодарность "petrd" за создание и наполнение этой темы на форуме. Эта ветка реально заменяет множество учебников.[Ответ]
ra9cim 07:16 18.09.2020
Пётр, привет. Есть такая непонятка, третий день ничего не получается. Есть два контакта, при замыкании первого сигнала нет, а при замыкании обоих или размыкании сигнал должен быть, но работает только при разомкнутых и замкнутом первом. Как написать, чтобы оба вместе замкнутые давали сигнал? У меня никак. И так делал,
Какой контроллер?
Почему в программе цикла нет?
[Ответ]
ra9cim 10:59 18.09.2020
12f629, что цикла нет я заметил уже поздно, но, что интересно, при разомкнутых сигнал есть, при замыкании первого пропадает, и обратно. Может из-за этого и не заметил, что цикла нет. Добавлю, посмотрю, что получится. А всё-таки, какая запись более правильная?
[Ответ]
petrd 11:29 18.09.2020
Без цикла программа исполнится один раз и остановится. А из Ваших слов понятно, что что-то и потом происходит, отсюда возникает неоднозначность в оценке происходящего. И поэтому ответов у меня пока нет. Возможно строжевик срабатывает. Сначала сделайте цикл и покажите настройки битов конфигурации, а там посмотрим.
[Ответ]
ra9cim 11:48 18.09.2020
Буду у компа, посмотрю, но то, что при замыкании первого контакта и размыкании оно всё работает, это меня и смутило.
Сейчас с планшета.
[Ответ]
ra9cim 07:53 20.09.2020
Пётр, привет, добрался до компа, флаги стоят: MCLRE_ON, WDT_OFF, INTRC_OSC_NOCLKOUT. Добавил цикл, но ничего не изменилось.
[Ответ]
ra9cim 07:59 20.09.2020
И всё-таки, какая запись более правильная, первая или вторая? Ну не силён я на Си, только из-за пикушки начал усваивать.
Осваивать, долбаный Т9, делает, как хочет.
[Ответ]
petrd 08:19 20.09.2020
Сообщение от ra9cim:
Есть два контакта, при замыкании первого сигнала нет, а при замыкании обоих или размыкании сигнал должен быть
Ничего не понятно. И при замыкании обоих и при размыкании (чего, обоих)? Как это?
[Ответ]
ra9cim 08:50 20.09.2020
Когда оба замкнуты или разомкнуты, то сигнал есть, а когда замкнут первый, то сигнала нет. Это про контакты.
[Ответ]
petrd 09:36 20.09.2020
Сообщение от ra9cim:
Когда оба замкнуты или разомкнуты, то сигнал есть, а когда замкнут первый, то сигнала нет. Это про контакты.
Попробовал, получил кучу ошибок, самая первая "необъявленный идентификатор в выражении" там, где в main() первое обращение к On1 (if (On1){) всего 9 ошибок.
[Ответ]
Пётр, привет. Да, у меня такой вариант работает, но дело в том, что нужны чёткие 3 состояния: разомкнуты оба контакта-включено, замкнут 1-й контакт-выключено, замкнуты оба контакта-включено. Просто я пошёл по простому пути - сначала добиться правильной работы светодиода, а потом дописать необходимое.
[Ответ]