Свежие обсуждения
Микроконтроллеры

Ликбез по С для микроконтроллеров PIC

1 33 64

Спасибо за код для реализации RC-5. Буду пробовать. Хочу все запихнуть в PIC16F676.

 

Flop: Спасибо за код для реализации RC-5. Буду пробовать. Хочу все запихнуть в PIC16F676.
Забыл добавить для ясности код настройки для PIC18.
//========================================================
#define IR_RB0 input(PIN_B0) // Порт приема команд от ПДУ

void main(void) {
disable_interrupts(global);
set_tris_b(0b11100001);
ext_int_edge(0, H_TO_L);
enable_interrupts(INT_EXT);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);
enable_interrupts(global);
{
while(TRUE) {
if (FLAG_IrDa==1) // опрос флага приема от ПДУ
{
Dec_IrDa(data); // если был прием от ПДУ - декодируем
FLAG_IrDa=0; // исполняем и сброс флага
enable_interrupts(global);
}
}

 

Для Welcome61. так полагаю вы давно занимаетесь контроллерами или разбираетесь
Написал программку для широтноимпульсной модуляции на одной из ног
и просто генератор на другой.

#include <16F676.h>
#device ADC=10
#use delay(clock=4000000)
#fuses INTRC, NOWDT
#byte ADCON0 = 0x1F
#include <adc.h> //Почему-то ССS этот файл не находит?

int32 n;
int32 t;
/////////////////////////////////////////////////////////////////////////////////////////
//_________Организация прерывания от таймера__________
//дополнения в программе на столько правильны- насколько я разобрался сам
int c0;

#int_timer0
void timer0_isr(void)
{
if (c0++ & 8)
output_bit(PIN_C2, 1);
//На ноге С2 должна быть генерация примерно со скважностью 2
else
output_bit(PIN_C2, 0);
}
/////////////////////////////////////////////////////////////////////////////////////////
//Разрешение на прерывание и кратность деления основного генератора
void generator(void) {
setup_counters(RTCC_INTERNAL, RTCC_DIV_2);
enable_interrupts(int_timer0);
enable_interrupts(global);
while(1);
}

void main(){ // Главная программа
generator();
while (1){
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(2); //потенциометр на канале 2
ADCON0 |= 2; //команда на начало оцифровки
n = read_adc() ;
set_adc_channel(0); //начать преобразование на канале 0
ADCON0 |= 2; //запуск
t = read_adc() ; //Присвоение переменной t результ. оцифровки
output_high(PIN_C1); ////////
delay_ms(n/10); //////// ШИМ
output_low(PIN_C1); ////////
delay_ms(t/10); ////////
}
}
Вопрос?
Почему генерация от таймера есть, а ШИМ не работает.
Отключаю таймер, тогда работает. Впечатление будто программа не доходит до куска ШИМ

 

Для Welcome61. так полагаю вы давно занимаетесь контроллерами или разбираетесь
Написал программку для широтноимпульсной модуляции на одной из ног
и просто генератор на другой.

#include <16F676.h>
#device ADC=10
#use delay(clock=4000000)
#fuses INTRC, NOWDT
#byte ADCON0 = 0x1F
#include <adc.h> //Почему-то ССS этот файл не находит?

int32 n;
int32 t;
/////////////////////////////////////////////////////////////////////////////////////////
//_________Организация прерывания от таймера__________
//дополнения в программе на столько правильны- насколько я разобрался сам
int c0;

#int_timer0
void timer0_isr(void)
{
if (c0++ & 8)
output_bit(PIN_C2, 1);
//На ноге С2 должна быть генерация примерно со скважностью 2
else
output_bit(PIN_C2, 0);
}
/////////////////////////////////////////////////////////////////////////////////////////
//Разрешение на прерывание и кратность деления основного генератора
void generator(void) {
setup_counters(RTCC_INTERNAL, RTCC_DIV_2);
enable_interrupts(int_timer0);
enable_interrupts(global);
while(1);
}

void main(){ // Главная программа
generator();
while (1){
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(2); //потенциометр на канале 2
ADCON0 |= 2; //команда на начало оцифровки
n = read_adc() ;
set_adc_channel(0); //начать преобразование на канале 0
ADCON0 |= 2; //запуск
t = read_adc() ; //Присвоение переменной t результ. оцифровки
output_high(PIN_C1); ////////
delay_ms(n/10); //////// ШИМ
output_low(PIN_C1); ////////
delay_ms(t/10); ////////
}
}
Вопрос?
Почему генерация от таймера есть, а ШИМ не работает.
Отключаю таймер, тогда работает. Впечатление будто программа не доходит до куска

 

У себя я генерировал ШИМ следующим образом:

...
#define Led0ON #asm bsf PORTB,0 #endasm //Включение светодиодов
#define Led0OFF #asm bcf PORTB,0 #endasm //Выключение светодиодов
...
unsigned char ShimTimer; //ШИМ-счетчик
...
#int_RTCC //Прерывание от таймера
void RTCC_isr(void)
{
if (LedT>=ShimTimer) Led0ON else Led0OFF;
.....
ShimTimer=ShimTimer+5;
}
....

в переменную LedT заносится соответствующий уровень (от 0 до 255).

Flop: Впечатление будто программа не доходит до куска ШИМ
1. зачем в цикле каждый раз настраивать АЦП?
2. может стоит подождать завершения преобразования перед READ_ADC()?
while (ADCON0 & 0b00000010); //Ожидаем завершение преобразования
3. У Вас ШИМ генеруруется одновременно и с помощью прерывания и в теле программы на одной ножке?
4. После выбора канала следует подождать, пока зарядится конденсатор АЦП (перед слудующей попыткой преобразования).
5. После преобразования следует подождать, пока зарядится конденсатор АЦП (перед слудующей попыткой преобразования).
6. В конце функции generator(); у Вас дальнейшее выполнение основного кода останавливается. Работает только прерывание.

 

Flop: Написал программку для широтноимпульсной модуляции на одной из ног
и просто генератор на другой.

Сергей К ответил Вам.
АЦП необходимо и достаточно настроить один раз для Вашей задачи.
И первое что бросилось в глаза - это while(1), которое и основном main() и в подпрограмме generator() .
Алгоритм нуждается в корректировке.
Про АЦП ---- я так делаю ( посмотрите листинг ассемблера и увидите, есть ли там проверка конца преобразования или нет)
delay_us(число);
set_adc_channel(0);
delay_us(число);
N_1_channel=read_adc(); //опрос 1 канала

set_adc_channel(2);
delay_us(число);
N_2_channel=read_adc(); //опрос 2 канала

 

Для С е р г е й К:
1. зачем в цикле каждый раз настраивать АЦП?
2. может стоит подождать завершения преобразования перед READ_ADC()?
while (ADCON0 & 0b00000010); //Ожидаем завершение преобразования
3. У Вас ШИМ генеруруется одновременно и с помощью прерывания и в теле программы на одной ножке?
4. После выбора канала следует подождать, пока зарядится конденсатор АЦП (перед слудующей попыткой преобразования).
5. После преобразования следует подождать, пока зарядится конденсатор АЦП (перед слудующей попыткой преобразования).
6. В конце функции generator(); у Вас дальнейшее выполнение основного кода останавливается. Работает только прерывание
1. Я взял пример использования АЦП из книги Шпака. А потом просто прикинул что можно сделать чтоб два канала опросить. Ошибку понял, попробую переписать.
2. Уверен что стоит подождать... Только в моей документации на 16F676 ADCON0
3-ий бит.
3. Нет не на одной. Шим для управления мощностью. А генератор на таймере - как задающий для инвертора.
4. В даташите так и написано, но я наивно надеялся, что эти задержки возьмет на себя CCS - PICC.
5. --//---//-- См. пункт 4.
6. Значит в подпрограмме generator() нужно убрать while(1); ? Я правильно понял?

Спасибо.

 

Flop: Только в моей документации на 16F676 ADCON0
там я проверяю флаг завершения преобразования.

Flop: Значит в подпрограмме generator() нужно убрать while(1); ? Я правильно понял?
while(1); - это значит зациклится навсегда.
Здесь два оператора:
"while(1)" - признак цикла. В данном случае условие завершение цикла никогда не наступит (условие всегда "1").
";" - пустая команда (nop в ассемблере).
в результате while бесконечно будет вызывать команду "nop". Если включены прерывания, то они будут выполнятся (т.к. при этом выполнение основного кода останавливается и указатель переходит по адрессу прерывания).

Во втором случае "while(1)" у Вас выполняются все команды, которые заключены в фигурные скобки {} сразу за оператором while.

И на последок. Возьмите бумажку и вручную пройдтиесь по коду Вашей программы и посмотрите как у Вас изменяется стостояние ножки С1 при разном значении АЦП. Будет очень нагляно показана работа алгоритма.

Flop: READ_ADC()... CCS - PICC
посмотрите список аргументов для READ_ADC(). Там есть команды, которые заставляют отрабатывать задержки на преобразования и т.д.

 

Здравствуйте!
Хотелось бы поблагодарить за форум и эту тему в частности. Спасибо! (тьфу-тьфу не сглазить бы!).
По теме - сейчас уже недели 3-4 юзаю отладчик клон-ICD-U40 и отлаживаюсь прямо в среде CCS, т.е.: написал код, скомпилировал и включаешь сразу этот отладчик(кнопка с "Божьей коровкой") и уже при подключенном отладчике и железе соответственно можно наблюдать и отлаживать работу устройства в реале. НЕплохо по-моему. Есть еще непроверенная инфа, что якобы существует плагин для PCM и пр. для возможности работы с мплабовским ИСД2.

 

В теме в кратце говорилось о прерываниях по изменению уровня на входах RB4-RB7 (PIC16F628A), но без конкретики, а хотелось бы ясности...

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

Ведь, по логике работы, МК сам непрерывно проверяет текущее состояние этих входов в каждом такте М1 и сравнивает его с предущим сохранённым состоянием. Если они одинаковы, то прерывания нет, а если разные, то происходит прерывание (если разрешено).
То есть, логика работы напоминает аппаратную защиту от дребезга кнопок с помощью триггера - первый же перепад переключает триггер в другое устойчивое состояние и не взирая на дребезг кнопки выдает на выходе стабильный уровень.

То есть, прочитав по прерыванию состояние порта B, я, вроде бы, могу сразу определить, какая кнопка была нажата.
Или нет, и мне, всё равно, придётся делать программную защиту от дребезга?