Технический форум по робототехнике.
PWM1_Init(5000);
PWM1_Set_Duty (192);
unsigned short current_duty, old_duty, current_duty1, old_duty1;
void InitMain() {
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
PORTA = 255;
TRISA = 255; // configure PORTA pins as input
PORTB = 0; // set PORTB to 0
TRISB = 0; // designate PORTB pins as output
PORTC = 0; // set PORTC to 0
TRISC = 0; // designate PORTC pins as output
PWM1_Init(5000); // Initialize PWM1 module at 5KHz
PWM2_Init(5000); // Initialize PWM2 module at 5KHz
}
void main() {
InitMain();
current_duty = 16; // initial value for current_duty
current_duty1 = 16; // initial value for current_duty1
PWM1_Start(); // start PWM1
PWM2_Start(); // start PWM2
PWM1_Set_Duty(current_duty); // Set current duty for PWM1
PWM2_Set_Duty(current_duty1); // Set current duty for PWM2
while (1) { // endless loop
if (RA0_bit) { // button on RA0 pressed
Delay_ms(40);
current_duty++; // increment current_duty
PWM1_Set_Duty(current_duty);
}
if (RA1_bit) { // button on RA1 pressed
Delay_ms(40);
current_duty--; // decrement current_duty
PWM1_Set_Duty(current_duty);
}
if (RA2_bit) { // button on RA2 pressed
Delay_ms(40);
current_duty1++; // increment current_duty1
PWM2_Set_Duty(current_duty1);
}
if (RA3_bit) { // button on RA3 pressed
Delay_ms(40);
current_duty1--; // decrement current_duty1
PWM2_Set_Duty(current_duty1);
}
Delay_ms(5); // slow down change pace a little
}
}
char data1[6];
char data2[6];
int x;
unsigned i;
void main()
{
Lcd_Init(&PORTD);
Lcd_Cmd(LCD_CURSOR_OFF); //курсор жки выключен
Lcd_Out(1,1,"ADC=");
Lcd_Out(2,1,"servo=");
TRISC.F5 =0; //инициализация серв на трех портах
TRISB.F4 =0;
TRISB.F5 =0;
while(1)
{
ANSEL=0xFF; //PORTA назначаем анлоговым
TRISA=0xFF; //PORTA назначаем входом
ADCON0=0b11001101; //режим: RC_Mode (11) ANALOG1(0011) GO(0) ADON(1)
ADCON0.GO=1; //запуск цикла аналогово-цифрового преобразователя
while(ADCON0.GO); // ожидание завершения преобразования
{
x=(ADRESH*4)+(ADRESL/64); // расчет полученных данных
WordToStr(x,data1); //преобразуем Х для вывода на экран
Lcd_Out(1,12,data1); // выводим на экран
Delay_ms(100); // в течении 100 миллисекунд
i=(1900/100)*(x/(1023/100)); // пропорция для зависимости частоты АЦП и импульсов для сервы
i=i+500; // прибавляем 500 чтобы самое маленькое значение для сервы было не менее 500 (500 - это крайнее левое положение, правое 2400)
i=i/1000; // делим на 1000 для перевода микросекунд в миллисекунды, потому что функция Vdelay_ms(i); работает только с миллисекундами. Хотя этот момент я сам не очень понимаю.
// Если мы задаем i от 500-2400 то почему бы Vdelay_ms(i); не принимать их за миллисекунды? Впрочем если на 1000 не делить - то работать вообще не будет...
WordToStr(i,data2);
Lcd_Out(2,12,data2);
Delay_ms(100);
ANSEL=0x00;
ANSELH=0x00;
PORTC.F5=1; //команды работать соответствующим выходам
PORTB.F5=1;
PORTB.F4=1;
Vdelay_ms(i);
PORTC.F5=0;
PORTB.F5=0;
PORTB.F4=0;
delay_ms(20); // самое интересное, что если убрать эту строчку программа будет работать абсолютно также, и серва будет точно также колбаситься...
}
}
}
x=(ADRESH*4)+(ADRESL/64); // вычисление частоты процессора
Zeus писал(а)::)).
2. Процедура VDelay_Advanced_ms (изначально предназначена для генерации милисекунд)
Prototype - void VDelay_Advanced_ms(unsigned time_in_ms, unsigned Current_Fosc_kHz);
Description Creates a software delay in duration of time_in_ms milliseconds (a variable), for a given oscillator frequency. Generated delay is not as precise as the delay created by Delay_ms.
Программная задержка в "реальных" "time_in_ms" милисекунах, которая привязана к частоте кварца.
Example pause = 1000;
fosc = 10000; (Частоту вводим в килогерцах, т.е. 10МГц/1000=10000 кГц)
VDelay_Advanced_ms(pause, fosc); // Generates approximately one second pause, for a oscillator frequency of 10 MHz
unsigned = 0...65535, так что максимум типа 65,535 МГц.
Так что четкие и правильные микросекунды этой процедурой не получить.
При кварце 10МГц можно конечно ввести 50000, тогда при time_in_ms = 1 может быть задержка будет 0,2 мс или 200 мкс...
Zeus писал(а): При кварце 10МГц можно конечно ввести 50000, тогда при time_in_ms = 1 может быть задержка будет 0,2 мс или 200 мкс...
- скорее всего так, типа занижаем тактовую частоту, а реально он на 10 МГц шпарит, может быть и так... я ошибочно увеличил в 5 раз.При кварце 10МГц нужно ввести 2000
в пару ADRESH и ADRESL записывается результат анлогово-цифрового преобразования и для того чтобы использовать полученные данные мы их вычисляем
Да это я понимаю, комментарий то написан "x=(ADRESH*4)+(ADRESL/64); // вычисление частоты процессора"
вот и спрашиваю причем здесь вычиление частоты процессора, когда вычисляешь данные с АЦП?
ANSEL=0xFF; //PORTA назначаем анлоговым
ANSEL=0x00;
ANSELH=0x00;
Zeus писал(а):я что-то не пойму, у тебя какой контроллер - PIC16F877?
Zeus писал(а):вот сижу листаю даташит и не могу найти там никакого регистра
- Код: Выделить всё • Развернуть
ANSEL=0xFF; //PORTA назначаем анлоговым
и вот эти тоже:
- Код: Выделить всё • Развернуть
ANSEL=0x00;
ANSELH=0x00;
в этих контроллерах вроде ADCON0 и ADCON1 только есть и ADRESH с ADRESL соответственно.
Регистр ADCON0 используется для настройки работы модуля АЦП, а с помощью регистра ADCON1 устанавливаются какие входы микроконтроллера будут использоваться модулем АЦП и в каком режиме (аналоговый или цмфровой порт вводаввывода).
Если у тебя действительно PIC16F877, то перечитай раздел 11 (модуль АЦП) даташита.
да ты не спеши все сделаешь и разберешься
Zeus писал(а):можно узнать, а зачем вообще такая формула сложная: x=(ADRESH*4)+(ADRESL/64)
зачем ADRESH умножать на 4, а ADRESL делить на 64 и потом все это складывать?
Помимо вышеприведенных микроконтроллеров, Microchip продолжает выпуск "устаревших" семейств (PIC16F627A/628A/648A, PIC16F72/73/74/76/77, PIC16F737/747/767/777, PIC16F818/819, PIC16F84(A), PIC16F87/88, PIC16F87x/87xA). Следует обратить внимание, что в большинстве случаев возможно и целесообразно осуществить переход к более новому семейству, обеспечивающему ту же функциональность, что позволит значительно сэкономить