Модераторы: Death_Morozz, null, Ale
taran_ob писал(а):Имел ввиду что хотелось в файлике на цифры посмотреть
taran_ob писал(а):То есть тестовая траектория только синус или может быть произвольная?
Ale писал(а):Я бы остановился на периоде передачи данных из игры порядка 5..10 мс (что дает нам в идеале возможность ощущать пятой точкой почти звуковые колебания до 100 (50) Гц при наезде на поребрики/бордюры).
taran_ob писал(а):Вот о чем подумал, как то пытался сделать гравировальную головку для станка из привода позиционирования головок харда. Так вот при 30-50 Гц она уже практически не стучала, при том что веса у нее никакого. То есть, сомневаюсь, что платформа будет эффективно справляться с таким заданием, по крайней мере с резиновоременным приводом. Да и редуктор в вайпере сдохнет быстро.
taran_ob писал(а):Может лучше в твою программу для компа внедрить алгоритм-фильтр который будет отслеживать гармонические колебания и по их амплитуде (или частоте) слать данные на контроллер вместе с координатой. А контроллер в свою очередь формирует отдельный канал с ШИМ для вибромотора.
Ale писал(а):Генератор может давать синус и меандр. + любую последовательность, которую ты ручками запишешь... в виде колонки цифр...
Ale писал(а):Он развивает свой продукт как раз в сторону увеличения скорости передачи координат.
Ale писал(а):В общем, давай пересмотрим, ну, скажем на те же 33мс.
Ale писал(а):Усложним механику, как мне кажется.
Ale писал(а):Типа как на руле сделано
Ale писал(а):
taran_ob писал(а):Может лучше в твою программу для компа внедрить алгоритм-фильтр который будет отслеживать гармонические колебания и по их амплитуде (или частоте) слать данные на контроллер вместе с координатой. А контроллер в свою очередь формирует отдельный канал с ШИМ для вибромотора.
Типа как на руле сделано . Усложним механику, как мне кажется. Хотя с точки зрения программ и контроллеров никаких сложностей нет
//Файлы/////////////////////////////////////////////////////////////////////////////////
#include <mega88.h>
#include <delay.h>
#include <stdio.h>
//Макросы/////////////////////////////////////////////////////////////////////////////////
#define BYTEH(word) (char)(word>>8)
#define BYTEL(word) (char)(word)
#define WORD(byteh,bytel) ((int)byteh<<8)|bytel
#define BYTE(nibbleh,nibblel) (nibbleh<<4)|nibblel
#define CLRBIT(byte, mask) byte&=~mask
#define SETBIT(byte, mask) byte|=mask
#define ABS(var) ((var) < 0 ? -(var) : (var))
//Команды///////////////////////////////////////////////////////////////////////////////////
#define WRITE_NORM_POSITION 0xFF
#define RESET_CONTROLLER 0x01
#define SAVE_CONST_TO_EEPROM 0x02
#define LOAD_DEFAULT_CONST 0x03
#define WRITE_POSITION 0x11
#define WRITE_VELOCITY 0x12
#define WRITE_PWM_MOTOR 0x13
#define WRITE_PWM_VIBRO 0x14
#define WRITE_KOEF_PROP 0x21
#define WRITE_KOEF_INT 0x22
#define WRITE_KOEF_VEL 0x23
#define WRITE_PWM_MIN 0x24
#define WRITE_PWM_MAX 0x25
#define WRITE_SOFT_LIM 0x26
#define WRITE_PWM_REF 0x27
#define WRITE_CONFIG 0x28
#define WRITE_USART_BAUND 0x31
#define WRITE_ID 0x32
#define READ_POSITION 0x41
#define READ_VELOCITY 0x42
#define READ_PWM_MOTOR 0x43
#define READ_PWM_VIBRO 0x44
#define READ_KOEF_PROP 0x51
#define READ_KOEF_INT 0x52
#define READ_KOEF_VEL 0x53
#define READ_PWM_MIN 0x54
#define READ_PWM_MAX 0x55
#define READ_SOFT_LIM 0x56
#define READ_PWM_REF 0x57
#define READ_CONFIG 0x58
#define READ_POSITION_RANGE 0x61
#define READ_KOEF_NORM 0x62
#define READ_VELOCITY_MAX 0x63
//Регистр UCSR0A////////////////////////////////////////////////////////////////////////////////////
#define PARITY_ERROR 0b00000100
#define DATA_OVERRUN 0b00001000
#define FRAMING_ERROR 0b00010000
#define DATA_REGISTER_EMPTY 0b00100000
#define RX_COMPLETE 0b10000000
//Регистр reg_flag///////////////////////////////////////////////////////////////////////////////////
#define FLAG_CALIB_COMPL 0b00000001
#define FLAG_CALIB_ERROR 0b00000010
#define FLAG_EN_CALC_VEL_GET 0b00000100
#define FLAG_MOTOR_OVL 0b00001000
#define FLAG_REQUEST_NEW 0b01000000
#define FLAG_RX_BUF_OVF 0b10000000
//Регистр reg_ctrl//////////////////////////////////////////////////////////////////////////////////
#define CTRL_CALIB_POS 0b00000000
#define CTRL_USART_POS_VEL_PWM 0b00000001
#define CTRL_USART_VEL_PWM 0b00000010
#define CTRL_USART_PWM 0b00000100
#define CTRL_ADC_POS_VEL_PWM 0b00001000
#define CTRL_ADC_VEL_PWM 0b00010000
#define CTRL_ADC_PWM 0b00100000
//Порты ввода-вывода///////////////////////////////////////////////////////////////////////////////////
#define PORT_PWM PORTB
#define MASK_PWM 0b00000110
#define MASK_PWMA 0b00000010
#define MASK_PWMB 0b00000100
#define PORT_DEF PINC
#define MASK_DEF 0b00001000
#define PORT_LIM PINC
#define MASK_LIM 0b00110000
#define MASK_LIM_L 0b00010000
#define MASK_LIM_R 0b00100000
#define PORT_ENC PIND
#define MASK_ENC 0b00001100
#define PORT_ENC_SHIFT ((PORT_ENC&MASK_ENC)>>2)
#define PORT_TXEN PORTD
#define MASK_TXEN 0b00010000
#define PORT_VIBRO PORTD
#define MASK_VIBRO 0b00100000
#define PORT_REF PORTD
#define MASK_REF 0b01000000
#define PORT_OVL PIND
#define MASK_OVL 0b10000000
#define PIN_POT 0x02
//Операции с регистрами///////////////////////////////////////////////////////////////////////////////
#define DO_CON_OCR1AB TCCR1A|=0b10100000;
#define DO_DISCON_OCR1AB TCCR1A&=0b01011111;
#define DO_CON_OCR1A TCCR1A&=0b11011111; TCCR1A|=0b10000000;
#define DO_CON_OCR1B TCCR1A&=0b01111111; TCCR1A|=0b00100000;
#define DO_CON_OCR0B TCCR0A|=0b00100000;
#define DO_DISCON_OCR0B TCCR0A&=0b11011111;
//Системные константы///////////////////////////////////////////////////////////////////////////////
#define FREQ_CLK 18432000 //Hz
#define FREQ_TIM0 288000 //Hz
#define FREQ_TIM2 2304000 //Hz
#define FREQ_CALC 100 //Hz
#define DIV_CALC 11 //DIV_CALC=FREQ_TIM0/256*FREQ_CALC
#define FREQ_SEND_ADC 10 //Hz
#define DIV_SEND_ADC 10 //DIV_CALC=FREQ_CALC/FREQ_SEND_ADC
#define MESSAGE_SIZE 5
#define RX_BUFFER_SIZE 32
#define TX_BUFFER_SIZE 32
#define HEADER 0x41
#define ID_INDIV_DOF1 0x01
#define ID_INDIV_DOF2 0x02
#define ADC_VREF_TYPE 0x20
//Умолчания///////////////////////////////////////////////////////////////////////////////
#define DEFAULT_K_PROP 50 //кэфф пропорциональный скорости
#define DEFAULT_K_INT 50 //кэфф интегральный скорости
#define DEFAULT_K_VEL 100 //кэфф пропорциональный скорости (FREQ_CALC скорость единичного перемещения при заданной частоте обновления координаты)
#define DEFAULT_PWM_MIN 0 //минимальный шим мотора
#define DEFAULT_PWM_MAX 1000 //максимальный шим мотора
#define DEFAULT_SOFT_LIM 100 //число шагов до концевика мертвой зоны
#define DEFAULT_PWM_REF 0 //0x007F//50% соответствует 2,5V/5=0.5V U=I*R U=10 A*0,1 Omh = 1V
#define DEFAULT_CONFIG 0x0000 //reg_flag reg_ctrl=CTRL_CALIB_POS
#define DEFAULT_BAUND (FREQ_CLK/(16*57600))-1 //57600 скорость СОМ порта
#define DEFAULT_ID 0x4201 //0x42 широковещание, 0x01 индивидуальный
//Константы в EEPROM//////////////////////////////////////////////////////////////////////////
///*
eeprom int eep_k_prop @0x10;
eeprom int eep_k_int @0x12;
eeprom int eep_k_vel @0x14;
eeprom int eep_pwm_min @0x16;
eeprom int eep_pwm_max @0x18;
eeprom int eep_soft_lim @0x1A;
eeprom int eep_pwm_ref @0x1C;
eeprom int eep_config @0x1E;
eeprom int eep_baund @0x20;
eeprom int eep_id @0x22;
//*/
unsigned int const_k_prop;
unsigned int const_k_int;
unsigned int const_k_vel;
unsigned int const_pwm_min;
unsigned int const_pwm_max;
unsigned int const_soft_lim;
unsigned int const_pwm_ref;
unsigned int const_config;
unsigned int const_baund;
unsigned int const_id;
//Константы/////////////////////////////////////////////////////////////////////////////////
unsigned char const_id_bdc;
unsigned char const_id_indiv;
unsigned char reg_flag;
unsigned char reg_ctrl;
unsigned int const_pos_range;
unsigned int const_k_norm;
unsigned int const_vel_max;
unsigned int const_adc_norm_vel;
unsigned int const_adc_norm_pwm;
unsigned char const_adc_pwm_min;
unsigned char const_adc_pwm_max;
//Переменные///////////////////////////////////////////////////////////////////////////////
unsigned char count_tim0_ovf;
unsigned char count_tim2_ovf;
unsigned char rx_wr_index, rx_rd_index, rx_counter;
unsigned char tx_wr_index, tx_rd_index, tx_counter;
char rx_buffer[RX_BUFFER_SIZE];
char tx_buffer[TX_BUFFER_SIZE];
unsigned char rx_id;
unsigned char rx_command;
unsigned char rx_data_h;
unsigned char rx_data_l;
unsigned char var_tim2_ovf;
unsigned char var_tcnt2;
signed int var_pos_set;
signed int var_pos_get;
signed int var_vel_set;
signed int var_vel_get;
signed int var_pwm_motor;
unsigned int var_pwm_vibro;
//Процедуры и функции////////////////////////////////////////////////////////////////////////////
//Инициализировать контроллер
void ini(void)
{
//UBRR0L=BYTEL(const_baund);
//OCR2A=BYTEL(const_pwm_ref);
//UBRR0L=(char)(FREQ_CLK/(16*const_baund*100))-1;
//TCCR0B=PRE_DIV_CLK_TIM0;
//OCR0A=(char)((FREQ_CLK/2*mas_div[PRE_DIV_CLK_TIM0]*FREQ_ENC_SCAN)-1);
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=In
// State7=P State6=P State5=P State4=P State3=P State2=0 State1=0 State0=P
PORTB=0xF9;
DDRB=0x06;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=P State5=P State4=P State3=P State2=T State1=T State0=T
PORTC=0x78;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=Out Func5=Out Func4=Out Func3=In Func2=In Func1=Out Func0=In
// State7=P State6=0 State5=0 State4=0 State3=P State2=P State1=0 State0=P
PORTD=0x8D;
DDRD=0x72;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 288,000 kHz
// Mode: Fast PWM top=0xFF
// OC0A output: Non-Inverted PWM
// OC0B output: Non-Inverted PWM
TCCR0A=0xA3;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 18432,000 kHz
// Mode: Fast PWM top=0x03FF
// OC1A output: Non-Inv.
// OC1B output: Non-Inv.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xA3;
TCCR1B=0x09;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 2304,000 kHz
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x02;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Any change
// INT1: On
// INT1 Mode: Any change
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x05;
EIMSK=0x03;
EIFR=0x03;
PCICR=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x01;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x01;
// ADC initialization
// ADC Clock frequency: 576,000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: ADC Stopped
// Only the 8 most significant bits of
// the AD conversion result are used
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On
DIDR0=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x85;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART0 Mode: Asynchronous
// USART Baud Rate: 57600
UCSR0A=0x00;
UCSR0B=0xD8;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x13;
// Global enable interrupts
#asm("sei")
}
//Конфигурировать контроллер
void config(void)
{
OCR0A=BYTEL(const_pwm_ref);
UBRR0L=BYTEL(const_baund);
reg_ctrl=BYTEL(const_config);
reg_flag=BYTEH(const_config);
const_id_bdc=BYTEH(const_id);
const_id_indiv=BYTEL(const_id);
}
//Сбросить контроллер
void resetchip(void)
{
#asm("cli")
DO_DISCON_OCR1AB;
CLRBIT(PORT_PWM, MASK_PWMA);
CLRBIT(PORT_PWM, MASK_PWMB);
count_tim0_ovf=0;
count_tim2_ovf=0;
rx_wr_index=0;
rx_rd_index=0;
rx_counter=0;
tx_wr_index=0;
tx_rd_index=0;
tx_counter=0;
rx_id=0;
rx_command=0;
rx_data_h=0;
rx_data_l=0;
var_tim2_ovf=0;
var_tcnt2=0;
var_pos_set=0;
var_pos_get=0;
var_vel_set=0;
var_vel_get=0;
var_pwm_motor=0;
var_pwm_vibro=0;
const_pos_range=0;
const_k_norm=0;
const_vel_max=0;
#asm("rjmp 0")
}
//Cохранить константы в EEPROM
void saveeep(void)
{
///*
eep_k_prop=const_k_prop;
eep_k_int=const_k_int;
eep_k_vel=const_k_vel;
eep_pwm_min=const_pwm_min;
eep_pwm_max=const_pwm_max;
eep_soft_lim=const_soft_lim;
eep_pwm_ref=const_pwm_ref;
eep_config=const_config;
eep_baund=const_baund;
eep_id=const_id;
//*/
}
//Прочитать константы по умолчанию
void loaddef(void)
{
const_k_prop=DEFAULT_K_PROP;
const_k_int=DEFAULT_K_INT;
const_k_vel=DEFAULT_K_VEL;
const_pwm_min=DEFAULT_PWM_MIN;
const_pwm_max=DEFAULT_PWM_MAX;
const_soft_lim=DEFAULT_SOFT_LIM;
const_pwm_ref=DEFAULT_PWM_REF;
const_config=DEFAULT_CONFIG;
const_baund=DEFAULT_BAUND;
const_id=DEFAULT_ID;
}
//Загрузить константы из EEPROM
void loadeep(void)
{
///*
const_k_prop=eep_k_prop;
const_k_int=eep_k_int;
const_k_vel=eep_k_vel;
const_pwm_min=eep_pwm_min;
const_pwm_max=eep_pwm_max;
const_soft_lim=eep_soft_lim;
const_pwm_ref=eep_pwm_ref;
const_config=eep_config;
const_baund=eep_baund;
const_id=eep_id;
//*/
}
//Организовать буфер приема
void rxfifo(void)
{
static char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer[rx_wr_index++]=data;
if (rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
if (++rx_counter == RX_BUFFER_SIZE)
{
rx_counter=0;
SETBIT(reg_flag, FLAG_RX_BUF_OVF);
}
}
}
//Организовать буфер отправки
void txfifo(void)
{
if (tx_counter)
{
--tx_counter;
UDR0=tx_buffer[tx_rd_index++];
if (tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
}
else CLRBIT(PORT_TXEN, MASK_TXEN);
}
/*
//Получить байт из буфера приема USART
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index++];
if (rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
//Отправить байт в буфер отправки USART
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
{
tx_buffer[tx_wr_index++]=c;
if (tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
++tx_counter;
}
else
{
SETBIT(PORT_TXEN, MASK_TXEN);
UDR0=c;
};
#asm("sei")
}
*/
//Получить результат АЦП
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
//delay_us(10); // Delay needed for the stabilization of the ADC input voltage
ADCSRA|=0x40; // Start the AD conversion
while ((ADCSRA & 0x10)==0); // Wait for the AD conversion to complete
ADCSRA|=0x10;
return ADCH;
}
//Принять запрос из буфера приема
void request(void) //на выходе rx_id, rx_command, rx_data_h, rx_data_l
{
if (rx_counter>=MESSAGE_SIZE) //если в буфере приема накопилось достаточно данных, то
{
while ((rx_counter>0)&&(getchar()!=HEADER)) {}; //считать байты из буфера пока не найден байт HEADER
if (rx_counter>=MESSAGE_SIZE-1) //если после этого осталось достаточно данных, то
{
rx_id=getchar(); //считать байт идентификатора
rx_command=getchar(); //считать код команды
rx_data_h=getchar(); //считать ст. байт данных
rx_data_l=getchar(); //считать мл. байт данных
if ((rx_id==const_id_bdc)||(rx_id==const_id_indiv)) //если считанный байт идентификатора совпадает с личным или широковещательным идентификатором, то
SETBIT(reg_flag, FLAG_REQUEST_NEW); //установить флаг нового запроса
}
}
}
//Обработать запрос
void task(unsigned char id, unsigned char command, unsigned char data_h, unsigned char data_l)
{
if (id==const_id_bdc)
{
switch (command)
{
case WRITE_NORM_POSITION: //Записать координату для 2х осей
{
switch (const_id_indiv)
{
case ID_INDIV_DOF1:
{
var_pos_set=data_h*const_k_norm;
break;
};
case ID_INDIV_DOF2:
{
var_pos_set=data_l*const_k_norm;
break;
};
};
break;
};
case RESET_CONTROLLER: //Выполнить сброс контроллера
{
resetchip();
break;
};
};
}
if (id==const_id_indiv)
{
switch (command)
{
//////////////////////////////////////////////////////////////////////
case WRITE_NORM_POSITION:
{
var_pos_set=data_l*const_k_norm;
var_pwm_vibro=data_h;
OCR0B=var_pwm_vibro;
break;
};
case WRITE_POSITION:
{
putchar(HEADER); putchar(id); putchar(READ_POSITION); putchar(BYTEH(var_pos_get)); putchar(BYTEL(var_pos_get));
var_pos_set=WORD(data_h,data_l);
break;
};
case WRITE_VELOCITY:
{
putchar(HEADER); putchar(id); putchar(READ_VELOCITY); putchar(BYTEH(var_vel_get)); putchar(BYTEL(var_vel_get));
var_vel_set=WORD(data_h,data_l);
break;
};
case WRITE_PWM_MOTOR:
{
putchar(HEADER); putchar(const_id_indiv); putchar(READ_VELOCITY); putchar(BYTEH(var_vel_get)); putchar(BYTEL(var_vel_get));
var_pwm_motor=WORD(data_h,data_l);
break;
};
case WRITE_PWM_VIBRO:
{
putchar(HEADER); putchar(id); putchar(READ_PWM_VIBRO); putchar(0x00); putchar(var_pwm_vibro);
var_pwm_vibro=data_l; OCR0B=var_pwm_vibro;
break;
};
//////////////////////////////////////////////////////////////////////
case READ_POSITION:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(var_pos_get)); putchar(BYTEL(var_pos_get));
break;
};
case READ_VELOCITY:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(var_vel_get)); putchar(BYTEL(var_vel_get));
break;
};
case READ_PWM_MOTOR:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(var_pwm_motor)); putchar(BYTEL(var_pwm_motor));
break;
};
case READ_PWM_VIBRO:
{
putchar(HEADER); putchar(id); putchar(command); putchar(0x00); putchar(BYTEL(var_pwm_vibro));
break;
};
//////////////////////////////////////////////////////////////////////
case WRITE_KOEF_PROP:
{
putchar(HEADER); putchar(id); putchar(READ_KOEF_PROP); putchar(BYTEH(const_k_prop)); putchar(BYTEL(const_k_prop));
const_k_prop=WORD(data_h, data_l);
break;
};
case WRITE_KOEF_INT:
{
putchar(HEADER); putchar(id); putchar(READ_KOEF_INT); putchar(BYTEH(const_k_int)); putchar(BYTEL(const_k_int));
const_k_int=WORD(data_h, data_l);
break;
};
case WRITE_KOEF_VEL:
{
putchar(HEADER); putchar(id); putchar(READ_KOEF_VEL); putchar(BYTEH(const_k_vel)); putchar(BYTEL(const_k_vel));
const_k_vel=WORD(data_h, data_l);
break;
};
case WRITE_PWM_MIN:
{
putchar(HEADER); putchar(id); putchar(READ_PWM_MIN); putchar(BYTEH(const_pwm_min)); putchar(BYTEL(const_pwm_min));
const_pwm_min=WORD(data_h, data_l);
break;
};
case WRITE_PWM_MAX:
{
putchar(HEADER); putchar(id); putchar(READ_PWM_MAX); putchar(BYTEH(const_pwm_max)); putchar(BYTEL(const_pwm_max));
const_pwm_max=WORD(data_h, data_l);
break;
};
case WRITE_SOFT_LIM:
{
putchar(HEADER); putchar(id); putchar(READ_SOFT_LIM); putchar(BYTEH(const_soft_lim)); putchar(BYTEL(const_soft_lim));
const_soft_lim=WORD(data_h, data_l);
break;
};
case WRITE_PWM_REF:
{
putchar(HEADER); putchar(id); putchar(READ_PWM_REF); putchar(0x00); putchar(BYTEL(const_pwm_ref));
const_pwm_ref=data_l; OCR0A=const_pwm_ref;
break;
};
case WRITE_CONFIG:
{
putchar(HEADER); putchar(id); putchar(READ_CONFIG); putchar(reg_flag); putchar(reg_ctrl);
const_config=WORD(data_h, data_l);
break;
};
case WRITE_USART_BAUND:
{
putchar(HEADER); putchar(id); putchar(command); putchar(0x00); putchar(UBRR0L);
const_baund=data_l;
break;
};
case WRITE_ID:
{
putchar(HEADER); putchar(id); putchar(command); putchar(const_id_bdc); putchar(const_id_indiv);
const_id=WORD(data_h, data_l);
break;
};
////////////////////////////////////////////////////////////////////
case READ_KOEF_PROP:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_k_prop)); putchar(BYTEL(const_k_prop));
break;
};
case READ_KOEF_INT:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_k_int)); putchar(BYTEL(const_k_int));
break;
};
case READ_KOEF_VEL:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_k_vel)); putchar(BYTEL(const_k_vel));
break;
};
case READ_PWM_MIN:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_pwm_min)); putchar(BYTEL(const_pwm_min));
break;
};
case READ_PWM_MAX:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_pwm_max)); putchar(BYTEL(const_pwm_max));
break;
};
case READ_SOFT_LIM:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_soft_lim)); putchar(BYTEL(const_soft_lim));
break;
};
case READ_PWM_REF:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_pwm_ref)); putchar(BYTEL(const_pwm_ref));
break;
};
case READ_CONFIG:
{
putchar(HEADER); putchar(id); putchar(command); putchar(reg_flag); putchar(reg_ctrl);
break;
};
case READ_POSITION_RANGE:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_pos_range)); putchar(BYTEL(const_pos_range));
break;
};
case READ_KOEF_NORM:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_k_norm)); putchar(BYTEL(const_k_norm));
break;
};
case READ_VELOCITY_MAX:
{
putchar(HEADER); putchar(id); putchar(command); putchar(BYTEH(const_vel_max)); putchar(BYTEL(const_vel_max));
break;
};
//////////////////////////////////////////////////////////////////////
case RESET_CONTROLLER:
{
if (WORD(data_h, data_l)&0xFFFF)
{
putchar(HEADER); putchar(id); putchar(command); putchar(0xFF); putchar(0xFF);
resetchip();
};
break;
};
case SAVE_CONST_TO_EEPROM:
{
if (WORD(data_h, data_l)&0xFFFF)
{
putchar(HEADER); putchar(id); putchar(command); putchar(0xFF); putchar(0xFF);
saveeep();
resetchip();
};
break;
};
case LOAD_DEFAULT_CONST:
{
if (WORD(data_h, data_l)&0xFFFF)
{
putchar(HEADER); putchar(id); putchar(command); putchar(0xFF); putchar(0xFF);
loaddef();
config();
};
break;
};
}
};
}
//Организовать связь по RS485
void simlink485(void)
{
if (tx_counter==0) //если буфер отправки пуст, то
{
request(); //проверить буфер приема на наличие нового запроса
if (reg_flag&FLAG_REQUEST_NEW) //если новый запрос, то
{
task(rx_id, rx_command, rx_data_h, rx_data_l); //выполнить задание
CLRBIT(reg_flag, FLAG_REQUEST_NEW); //сбросить флаг нового запроса
};
};
}
//Сканировать компаратор
void ovl(void)
{
if (PORT_OVL&MASK_OVL) {#asm("cli") OCR1AH=0; OCR1AL=0; OCR1BH=0; OCR1BL=0; #asm("sei")};
}
//Сканировать концевики
void limit(void)
{
if (PORT_LIM&MASK_LIM)
{
DO_DISCON_OCR1AB;//отключить OCR1A и отключить OCR1B
CLRBIT(PORT_PWM, MASK_PWMA);
CLRBIT(PORT_PWM, MASK_PWMB);
while(1){#asm("cli");};
}
}
//Сканировать енкодер
void encoder(void) //на выходе: var_position_get, var_tcnt2, var_count_tim2_ovf
{
static unsigned char enc_last, enc_now, enc_dir_last, enc_dir_now;
enc_now=PORT_ENC_SHIFT; //прочитать состояние энкодера и сдвинуть в начало байта
enc_dir_now=(enc_last&1)^((enc_now&2)>>1); //определить направление вращения
enc_last=enc_now; //текущее состояние энкодера стало прошлым
if (!enc_dir_now) var_pos_get++; //обновить текущую позицию в зависимости от направления вращения
else var_pos_get--;
if ((enc_dir_last==enc_dir_now)&&(reg_flag&FLAG_EN_CALC_VEL_GET)) //если направление вращения не поменялось, то
{
var_tcnt2=TCNT2; //присвоить глобальной переменной значение таймера2
var_tim2_ovf=count_tim2_ovf; //присвоить глобальной переменной число переполнений таймера2
};
enc_dir_last=enc_dir_now; //текущее направление вращения стало прошлим
CLRBIT(reg_flag, FLAG_EN_CALC_VEL_GET);
count_tim2_ovf=0; //сбросить счетчик переполнений таймера2
TCNT2=0; //сбросить таймер2
SETBIT(EIFR, 0b00000011); //сбросить флаги внешних прерываний
SETBIT(TIFR2, 0b00000001); //сбросить флаг переполнения таймера2
}
//Расчитать задание скорости
signed int calcvelset(signed int pos_set, signed int pos_get, unsigned int k_vel, unsigned int vel_max)
{
static unsigned int vel_set;
vel_set=k_vel*(pos_set-pos_get);
if (vel_set<vel_max) return vel_set;
else return vel_max;
}
//Расчитать фактическую скорость
unsigned int calcvelget(unsigned char count, unsigned char count_ovf)
{
return FREQ_TIM2/(count+(long int)count_ovf*255); //VEL=FREQ_CLC/Ncount частота следования квадратур энкодера
}
//Расчитать ШИМ
signed int calcpwm(signed int vel_set, signed int vel_get, unsigned int k_prop, unsigned int k_int, unsigned int pwm_min, unsigned int pwm_max)
{
static signed int pwm;
static signed int vel_error;
static signed int vel_sum_error;
vel_error=ABS(vel_set)-vel_get;
if ((pwm>pwm_min)&&(pwm<pwm_max)) vel_sum_error=vel_sum_error+vel_error;
pwm=(((long int)k_prop*vel_error)+((long int)k_int*vel_sum_error))/1000; //расчет воздействия
if ((pwm>pwm_min)&&(pwm<pwm_max))
{
if (vel_set>0) return pwm;
else return -pwm;
}
else
{
if (pwm>=pwm_max)
{
if (vel_set>0) return pwm_max;
else return -pwm_max;
}
else return 0;
}
}
//Установить ШИМ
void setmotor(signed int pwm)
{
static unsigned int pwm_abs;
pwm_abs=ABS(pwm);
if (pwm>0) {#asm("cli") OCR1BH=0; OCR1BL=0; OCR1AH=BYTEH(pwm_abs); OCR1AL=BYTEL(pwm_abs); #asm("sei")}
else {#asm("cli") OCR1AH=0; OCR1AL=0; OCR1BH=BYTEH(pwm_abs); OCR1BL=BYTEL(pwm_abs); #asm("sei")};
}
//Выполнять калибровку
void calib(void)
{
static unsigned char step;
switch (step)
{
case 0:
{
step=1;
var_pos_get=0;
var_pwm_motor=-(const_pwm_max/2);
setmotor(var_pwm_motor);
break;
};
case 1:
{
if (PORT_LIM&MASK_LIM_L)
{
step=2;
var_pos_get=0;
var_pwm_motor=const_pwm_max/2;
setmotor(var_pwm_motor);
delay_ms(100);
};
break;
};
case 2:
{
if (PORT_LIM&MASK_LIM_R)
{
step=3;
var_pwm_motor=0;
setmotor(var_pwm_motor);
delay_ms(100);
const_pos_range=var_pos_get-2*const_soft_lim;
const_k_norm=const_pos_range/256;
var_pos_get=const_pos_range+const_soft_lim;
};
break;
};
case 3:
{
step=4;
var_pwm_motor=-(const_pwm_max);
setmotor(var_pwm_motor);
break;
};
case 4:
{
if (var_pos_get<(const_pos_range/2))
{
step=0;
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
if (var_vel_get>const_vel_max) const_vel_max=var_vel_get;
var_pwm_motor=0;
setmotor(var_pwm_motor);
SETBIT(reg_flag, FLAG_CALIB_COMPL); //установить флаг "калибровка завершена"
}
else
{
if (PORT_LIM&MASK_LIM_L)
{
step=0;
var_pwm_motor=0;
setmotor(var_pwm_motor);
};
};
break;
};
};
}
//Задать позицию потенциометром
signed int adcposset(unsigned char pin, unsigned int k_norm)
{
return k_norm*read_adc(pin);
}
//Задать скорость потенциометром
signed int adcvelset(unsigned char pin, unsigned int k_norm_vel)
{
return k_norm_vel*(read_adc(pin)-127);
}
//Задать ШИМ потенциометром
signed int adcpwm(unsigned char pin, unsigned int k_norm_pwm, unsigned char adc_pwm_min, unsigned char adc_pwm_max)
{
static unsigned int adc;
adc=read_adc(pin);
if ((adc>adc_pwm_min)&&(adc<adc_pwm_max)) return 0;
else return k_norm_pwm*(adc-127);
}
//Прерывания///////////////////////////////////////////////////////////////////////////////
//Внешнее прерывание при изменении состояния канала А энкодера
interrupt [EXT_INT0] void ext_int0_isr(void)
{
encoder();
}
//Внешнее прерывание при изменении состояния канала В энкодера
interrupt [EXT_INT1] void ext_int1_isr(void)
{
encoder();
}
//Прерывание по переполнению таймера0 (1125Гц), для задачи частоты расчета ШИМ
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
count_tim0_ovf++;
if (!EIFR) SETBIT(reg_flag, FLAG_EN_CALC_VEL_GET); //если внешних прерываний не было, то разрешить захват таймера2 для расчета скорости
}
//Прерывание по переполнению таймера2 (9000Гц), для расчета скорости вращения энкодера
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
if (count_tim2_ovf<254) count_tim2_ovf++;
}
//Прерывание от USART по приему байта
interrupt [USART_RXC] void usart_rx_isr(void)
{
rxfifo();
if (!EIFR) SETBIT(reg_flag, FLAG_EN_CALC_VEL_GET); //если внешних прерываний не было, то разрешить захват таймера2 для расчета скорости
}
//Прерывание от USART после передачи байта
interrupt [USART_TXC] void usart_tx_isr(void)
{
txfifo();
if (!EIFR) SETBIT(reg_flag, FLAG_EN_CALC_VEL_GET); //если внешних прерываний не было, то разрешить захват таймера2 для расчета скорости
}
//Программа//////////////////////////////////////////////////////////////////////////////
void main(void)
{
static char count_calc;
static char ctrl_after_calib;
ini(); //Выполнить инициализацию контроллера
loadeep(); //Загрузить константы из EEPROM
config(); //Выполнить конфигурирование
if (!(PORT_DEF&MASK_DEF)) //Если при включении нажата кнопка DEF, то управление от ADC
{
delay_ms(100);
if (!(PORT_DEF&MASK_DEF))
ctrl_after_calib=CTRL_ADC_POS_VEL_PWM;
}
else ctrl_after_calib=CTRL_USART_POS_VEL_PWM; //иначе управление от USART
if (!(PORT_DEF&MASK_DEF)) //Если DEF нажата более 2с, то
{
delay_ms(2000);
if (!(PORT_DEF&MASK_DEF))
{
loaddef(); //использовать константы "по умолчанию"
config(); //выполнить конфигурирование
ctrl_after_calib=CTRL_USART_POS_VEL_PWM; //управление от USART
};
};
while(1) //Бесконечный программный цикл, переключение режимов контроллера через регистр reg_ctrl
{
while (reg_ctrl==CTRL_CALIB_POS) //Цикл калибровки
{
ovl();
calib();
if (reg_flag&FLAG_CALIB_COMPL)
{
var_pos_set=const_pos_range/2;
reg_ctrl=ctrl_after_calib;
//расчет констант для управления от ADC
const_adc_norm_vel=const_vel_max/128;
const_adc_norm_pwm=const_pwm_max/128;
const_adc_pwm_min=127-(const_pwm_min/const_adc_norm_pwm);
const_adc_pwm_max=127+(const_pwm_min/const_adc_norm_pwm);
};
};
while (reg_ctrl==CTRL_USART_POS_VEL_PWM) //Стабилизация принятой по USART позиции по скорости
{
simlink485();
ovl();
limit();
if (count_tim0_ovf==DIV_CALC)
{
count_tim0_ovf=0;
var_vel_set=calcvelset(var_pos_set, var_pos_get, const_k_vel, const_vel_max);
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
var_pwm_motor=calcpwm(var_vel_set, var_vel_get, const_k_prop, const_k_int, const_pwm_min, const_pwm_max);
setmotor(var_pwm_motor);
};
};
while (reg_ctrl==CTRL_USART_VEL_PWM) //Стабилизация принятой по USART скорости
{
simlink485();
ovl();
limit();
if (count_tim0_ovf==DIV_CALC)
{
count_tim0_ovf=0;
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
var_pwm_motor=calcpwm(var_vel_set, var_vel_get, const_k_prop, const_k_int, const_pwm_min, const_pwm_max);
setmotor(var_pwm_motor);
};
};
while (reg_ctrl==CTRL_USART_PWM) //Стабилизация принятой по USART ШИМ
{
simlink485();
ovl();
limit();
if (count_tim0_ovf==DIV_CALC)
{
count_tim0_ovf=0;
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
setmotor(var_pwm_motor);
};
};
while (reg_ctrl==CTRL_ADC_POS_VEL_PWM) //Стабилизация позиции заданной через ADC (для выхода из цикла требуется сброс контроллера)
{
ovl();
limit();
if (count_tim0_ovf==DIV_CALC)
{
count_tim0_ovf=0;
var_pos_set=adcposset(PIN_POT, const_k_norm);
var_vel_set=calcvelset(var_pos_set, var_pos_get, const_k_vel, const_vel_max);
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
var_pwm_motor=calcpwm(var_vel_set, var_vel_get, const_k_prop, const_k_int, const_pwm_min, const_pwm_max);
setmotor(var_pwm_motor);
if (count_calc++==DIV_SEND_ADC)
{
count_calc=0;
printf("Ps %d",var_pos_set); printf(" Pg %d",var_pos_get); printf("\n\r");
// putchar(HEADER); putchar(const_id_bdc); putchar(WRITE_POSITION); putchar(BYTEH(var_pos_set)); putchar(BYTEL(var_pos_set));
// putchar(HEADER); putchar(const_id_bdc); putchar(READ_POSITION); putchar(BYTEH(var_pos_get)); putchar(BYTEL(var_pos_get));
}
else
{
if (!(PORT_DEF&MASK_DEF))
{
while (!(PORT_DEF&MASK_DEF)){};
delay_ms(100);
reg_ctrl=CTRL_ADC_VEL_PWM;
};
};
};
};
while (reg_ctrl==CTRL_ADC_VEL_PWM) //Стабилизация скорости заданной через ADC (для выхода из цикла требуется сброс контроллера)
{
ovl();
limit();
if (count_tim0_ovf==DIV_CALC)
{
count_tim0_ovf=0;
var_vel_set=adcvelset(PIN_POT, const_adc_norm_vel);
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
var_pwm_motor=calcpwm(var_vel_set, var_vel_get, const_k_prop, const_k_int, const_pwm_min, const_pwm_max);
setmotor(var_pwm_motor);
if (count_calc++==DIV_SEND_ADC)
{
count_calc=0;
printf("Vs %d",var_vel_set); printf(" Vg %d",var_vel_get); printf("\n\r");
// putchar(HEADER); putchar(const_id_bdc); putchar(WRITE_VELOCITY); putchar(BYTEH(var_vel_set)); putchar(BYTEL(var_vel_set));
// putchar(HEADER); putchar(const_id_bdc); putchar(READ_VELOCITY); putchar(BYTEH(var_vel_get)); putchar(BYTEL(var_vel_get));
}
else
{
if (!(PORT_DEF&MASK_DEF))
{
while (!(PORT_DEF&MASK_DEF)){};
delay_ms(100);
reg_ctrl=CTRL_ADC_PWM;
};
};
};
};
while (reg_ctrl==CTRL_ADC_PWM) //Стабилизация ШИМ заданной через ADC (для выхода из цикла требуется сброс контроллера)
{
ovl();
limit();
if (count_tim0_ovf==DIV_CALC)
{
count_tim0_ovf=0;
var_vel_get=calcvelget(var_tcnt2, var_tim2_ovf);
var_pwm_motor=adcpwm(PIN_POT, const_adc_norm_pwm, const_adc_pwm_min, const_adc_pwm_max);
setmotor(var_pwm_motor);
if (count_calc++==DIV_SEND_ADC)
{
count_calc=0;
printf("PWM %d",var_pwm_motor); printf(" Vg %d",var_vel_get); printf("\n\r");
// putchar(HEADER); putchar(const_id_bdc); putchar(WRITE_PWM_MOTOR); putchar(BYTEH(var_pwm_motor)); putchar(BYTEL(var_pwm_motor));
// putchar(HEADER); putchar(const_id_bdc); putchar(READ_VELOCITY); putchar(BYTEH(var_vel_get)); putchar(BYTEL(var_vel_get));
}
else
{
if (!(PORT_DEF&MASK_DEF))
{
while (!(PORT_DEF&MASK_DEF)){};
delay_ms(100);
reg_ctrl=CTRL_ADC_POS_VEL_PWM;
};
};
};
};
}
}
Вернуться в X-SIMULATOR и RU-SIMULATOR & SimTools
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 155