итак,задача:
из игрового руля на 270 градусов сделать руль с возможностью изменения угла
реализация
я взял руль Thrustmaster Rallye GT Force Feedback Clutch,вынул из него потенциометр,поставил вместо него абсолютный энкодер BOURNS EAW0J-B24-AE0128L
его показания получаю в atmega8,считаю количество пройденных пинов и умножаю их на множитель(про него дальше) для получения значения,которое устанавливаю в OCR1A
про множитель
для начала надо повторить базовую реализацию угла в 270 градусов.у энкодера позиции 0-127,т.е. 360 градусов равняется 128 пинам.простой математикой получаем что угол 270 градусов это 96 пинов.ещё раз считаем и получаем что 1 пин равняется 2.83 градуса.вот соответственно множитель и устанавливаем в 2.83
но практика показала что 2.83 это и близко не то значение.реально я сейчас подобрал что примерно 5.5 это близкое значение,но и то это ещё не оно.это проблема номер раз
а проблема номер два это то что оно выходит на крайнее левое и крайнее правое значение при абсолютно разных значениях пройденных пинов.у руля есть штатная прога для калибровки,где наглядно можно наблюдать куда я его поворачиваю

я добавил кнопку програмной центровки руля,и пробовал центровать нормально,повёрнутым вправо,повёрнутым влево и повёрнутым на 180 градусов.вообще разное количество пинов от крайнего левого до крайнего правого положения.за середину при центровке всегда задаётся 48 пинов(якобы уже пройдено)-потому что 96\2:
крайнее левое: физический пин:114 пинов пройдено от 0:24 значение OCR1A:132 крайнее правое: физический пин:38 пинов пройдено от 0:76 значение OCR1A:418
крайнее левое: физический пин:11 пинов пройдено от 0:21 значение OCR1A:115 крайнее правое: физический пин:69 пинов пройдено от 0:79 значение OCR1A:434
крайнее левое: физический пин:121 пинов пройдено от 0:22 значение OCR1A:121 крайнее правое: физический пин:69 пинов пройдено от 0:98 значение OCR1A:539
разброс мягко говоря бредовый.
я не могу понять чем это обусловлено.вполне допускаю что я что-то не правильно указал в настройках ШИМа,поэтому я уже замахался искать сам проблему,прошу помощи у более опытных людей.ниже код проги,в ней много отладочного кода,тот-же вывод показаний на трёхциферный семисегментный индикатор пришлось сделать,чтоб увидеть в железе как оно считает.HELP
Код: Выделить всё
/*
* main.c
*
* Created: 1/4/2024 9:10:34 PM
* Author: sanitar
*/
#define F_CPU 8000000UL
//#define pin_per_angle 2.8
#include <avr/pgmspace.h>
#include <math.h>
//массив соответствия номера пина к его двоичному коду
const uint8_t pos_table[128] PROGMEM = {127,63,62,58,56,184,152,24,8,72,73,77,79,15,47,175,191,159,31,29,28,92,76,12,4,36,164,166,167,135,151,215,223,207,143,142,14,46,38,6,2,18,82,83,211,195,203,235,239,231,199,71,7,23,19,3,1,9,41,169,233,225,229,245,247,243,227,163,131,139,137,129,128,132,148,212,244,240,242,250,251,249,241,209,193,197,196,192,64,66,74,106,122,120,121,125,253,252,248,232,224,226,98,96,32,33,37,53,61,60,188,190,254,126,124,116,112,113,49,48,16,144,146,154,158,30,94,95};
int A1,A2,A3;
void number(int numb)
{
//список портов для каждой цифры в индикаторе
switch (numb)
{
case 0:
PORTC |= 1<<0;
PORTB |= 1<<5;
PORTB |= 1<<2;
PORTC |= 1<<4;
PORTC |= 1<<3;
PORTC |= 1<<5;
break;
case 1:
PORTC |= 1<<5;
PORTB |= 1<<2;
break;
case 2:
PORTC |= 1<<0;
PORTB |= 1<<2;
PORTD |= 1<<0;
PORTC |= 1<<4;
PORTC |= 1<<3;
break;
case 3:
PORTC |= 1<<0;
PORTB |= 1<<2;
PORTD |= 1<<0;
PORTC |= 1<<5;
PORTC |= 1<<3;
break;
case 4:
PORTB |= 1<<5;
PORTD |= 1<<0;
PORTB |= 1<<2;
PORTC |= 1<<5;
break;
case 5:
PORTC |= 1<<0;
PORTB |= 1<<5;
PORTD |= 1<<0;
PORTC |= 1<<5;
PORTC |= 1<<3;
break;
case 6:
PORTC |= 1<<0;
PORTB |= 1<<5;
PORTD |= 1<<0;
PORTC |= 1<<4;
PORTC |= 1<<5;
PORTC |= 1<<3;
break;
case 7:
PORTC |= 1<<0;
PORTB |= 1<<2;
PORTC |= 1<<5;
break;
case 8:
PORTC |= 1<<0;
PORTB |= 1<<5;
PORTD |= 1<<0;
PORTB |= 1<<2;
PORTC |= 1<<4;
PORTC |= 1<<5;
PORTC |= 1<<3;
break;
case 9:
PORTC |= 1<<0;
PORTB |= 1<<5;
PORTD |= 1<<0;
PORTB |= 1<<2;
PORTC |= 1<<5;
PORTC |= 1<<3;
break;
}
}
void blackout()
{
//гасим транзисторы
PORTD&=~(1<<1);
PORTC&=~(1<<1);
PORTC&=~(1<<2);
/////
//гасим сегменты
PORTC&=~(1<<0);
PORTB&=~(1<<5);
PORTD&=~(1<<0);
PORTB&=~(1<<2);
PORTC&=~(1<<4);
PORTC&=~(1<<5);
PORTC&=~(1<<3);
////
}
void show_digit(int pos)
{
//цифровой индикатор
A1=pos%10; // 1ый разряд
A2=(pos%100)/10; // 2ой разряд
A3=pos/100; // 3ий разряд
blackout();
if (pos<10)
{
number(pos);
PORTC|=1<<1;
}
if ((pos>=10) && (pos<100))
{
number(A1);
PORTC|=1<<1;
blackout();
number(A2);
PORTC|=1<<2;
blackout();
}
if (pos>=100)
{
number(A1);
PORTC|=1<<1;
blackout();
number(A2);
PORTC|=1<<2;
blackout();
number(A3);
PORTD|=1<<1;
}
}
int main(void)
{
char initialisation,can_toggle_angle,angle_toggler_itter;
int p[8],tmp,forwarded,enc_pos,last_enc_pos,wheel_pos,electricity_pos,wheel_center,max_perm_pins;
float voltage_modifier;
initialisation=0;
last_enc_pos=0;
enc_pos=0;
wheel_pos=0;
electricity_pos=0;
wheel_center=48;
max_perm_pins=96;
voltage_modifier=5.5;
angle_toggler_itter=0;
DDRD=0x00;
DDRB&=~(1<<0); //PB0 read
DDRB|=1<<1; //PB1 write
DDRB&=~(1<<2); //PB3 read
DDRB&=~(1<<3); //PB4 read
DDRB&=~(1<<5); //PB6 read
DDRB&=~(1<<6); //PB7 read
PORTB |= 0<<1;
PORTB |= 0<<0;
TCCR1A = 0b10000010;
TCCR1B = 0b00011001;
ICR1=0x21C;
OCR1A=0x00;
//порты для индикатора
DDRD|=1<<0;
DDRB|=1<<2;
DDRB|=1<<5;
DDRC|=1<<0;
DDRC|=1<<3;
DDRC|=1<<4;
DDRC|=1<<5;
//порты для транзисторов
DDRD|=1<<1;
DDRC|=1<<1;
DDRC|=1<<2;
p[0]=0;
p[1]=0;
p[2]=0;
p[3]=0;
p[4]=0;
p[5]=0;
p[6]=0;
p[7]=0;
while (1)
{
tmp=0;
if (!bit_is_clear(PINB,4))
{
initialisation=0;
}
if (bit_is_clear(PINB,3))
{
can_toggle_angle=1;
}
/*
закоменчено ибо не могу 270 добиться,куда мне больший угол
if (!bit_is_clear(PINB,3))
{
if (can_toggle_angle==1)
{
angle_toggler_itter++;
initialisation=0;
if (angle_toggler_itter>3)
{
angle_toggler_itter=0;
}
if (angle_toggler_itter==0)
{
//angle 270
voltage_modifier=5.45;
wheel_center=48;
max_perm_pins=96;
}
if (angle_toggler_itter==1)
{
//angle 360
voltage_modifier=5.3;
wheel_center=48;
max_perm_pins=96;
}
if (angle_toggler_itter==2)
{
//angle 900
voltage_modifier=5.2;
wheel_center=48;
max_perm_pins=96;
}
if (angle_toggler_itter==3)
{
//angle 1080
voltage_modifier=5.1;
wheel_center=48;
max_perm_pins=96;
}
}
can_toggle_angle=0;
}
*/
//считывание позиции энкодера по 8 ногам
if (!bit_is_clear(PINB,0))
{
p[0]=1;
}
else
{
p[0]=0;
}
if (!bit_is_clear(PIND,7))
{
p[1]=1;
}
else
{
p[1]=0;
}
if (!bit_is_clear(PIND,6))
{
p[2]=1;
}
else
{
p[2]=0;
}
if (!bit_is_clear(PIND,5))
{
p[3]=1;
}
else
{
p[3]=0;
}
if (!bit_is_clear(PINB,7))
{
p[4]=1;
}
else
{
p[4]=0;
}
if (!bit_is_clear(PINB,6))
{
p[5]=1;
}
else
{
p[5]=0;
}
if (!bit_is_clear(PIND,3))
{
p[6]=1;
}
else
{
p[6]=0;
}
if (!bit_is_clear(PIND,4))
{
p[7]=1;
}
else
{
p[7]=0;
}
for (int i = 0; i < 8; i++)
{
//перевод из двоичной в десятичную
int x=(8-i)-2;
forwarded=2;
if (i==7)
{
forwarded=1;
}
while (x>0)
{
forwarded=forwarded*2;
x--;
} ;
tmp=tmp+p[i]*forwarded;
}
for (int i = 0; i < 128; i++)
{
//получение позиции энкодера по таблице соответствия
if (pgm_read_byte(&pos_table[i])==tmp)
{
enc_pos=i;
break;
}
}
if (initialisation==0)
{
//инициализационный сброс(центровка)
last_enc_pos=enc_pos;
initialisation=1;
wheel_pos=wheel_center;
electricity_pos=0x10E;
}
if (enc_pos>last_enc_pos)
{
if ((last_enc_pos>=0) && (last_enc_pos<30) && (enc_pos<=127) && (enc_pos>100))
{
wheel_pos=wheel_pos-(last_enc_pos+(128-enc_pos));
}
else
{
wheel_pos=wheel_pos+(enc_pos-last_enc_pos);
}
}
if (enc_pos<last_enc_pos)
{
if ((last_enc_pos>100) && (last_enc_pos<=127) && (enc_pos>=0) && (enc_pos<30))
{
wheel_pos=wheel_pos+((128-last_enc_pos)+enc_pos);
}
else
{
wheel_pos=wheel_pos-(last_enc_pos-enc_pos);
}
}
/*
ограничители закоменчено специально для отладки
if (wheel_pos>max_perm_pins)
{
wheel_pos=max_perm_pins;
}
if (wheel_pos<0)
{
wheel_pos=0;
}
*/
last_enc_pos=enc_pos;
electricity_pos=floor(wheel_pos*voltage_modifier);
//код для вывода данных на индикатор
if (!bit_is_clear(PINB,3))
{
if (can_toggle_angle==1)
{
angle_toggler_itter++;
if (angle_toggler_itter>2)
{
angle_toggler_itter=0;
}
can_toggle_angle=0;
}
}
if (angle_toggler_itter==0)
{
show_digit(enc_pos);
}
if (angle_toggler_itter==1)
{
show_digit(wheel_pos);
}
if (angle_toggler_itter==2)
{
show_digit(electricity_pos);
}
//конец вывода
//
OCR1A=electricity_pos;
}
}
да.совсем забыл,могу дать проект в протеусе.хотя не знаю нужен-ли,ведь по железу всё работает.
UPD2:а может и в железе.на ноге ШИМа ещё стоит ФНЧ такого типа,и только после этого идёт уже питание в управляющую схему руля

