A program alapját a kedvenc soros portos kommunikációs terminálom illetve annak forráskódja adta, amelyik elerheto itt. Lényege, hogy az inverz kinematika számoló programban kigenerált értékeket fel tudjam tölteni a MicronRam-ba mindenféle fennakadás nélkül. Ezekre az értékekre azért van szükség, mert egyelőre nehéz lenne valós időben kiszámolni a szervók megfelelő pozícióit illetve értékeit.
A program a következőképpen néz ki :
Három fontos egysége van: bemeneti, beállítás és kimeneti. A bemeneti részben tudjuk megadni, hogy melyik állományt szeretnénk feltölteni. A beállítások résznél tudjuk kiválasztani a rendelkezésre álló soros portok közül, hogy melyiken keresztül szeretnénk kommunikálni, illetve, hogy melyik "particiót" szeretnénk felülírni. Kimeneti egységek a hiba ablak, az előnézet ablak, illetve az érkezett üzenetek ablak. A hiba ablakba kerül minden, amit a try-catch blokk kidob magából, illetve ide kerülnek a "nem megfelelően formázott " tipusú szövegek is. Az előnézet ablakban láthatjuk a kódot, amit feltöltünk az FPGA-ra. Ugyanitt módosításokat is eszközölhetünk, mivel módosítás esetén az itt megjelenített kód lesz feltöltve, s nem az, ami a szöveges állományban van. Az érkezett üzenetek ablakban jelennek meg az FPGA által küldött üzenetek. Itt kisérhetjük figyelemmel, hogy a küldés sikeres volt, vagy sem.
Fontosabb forráskód részletek :
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// If the com port has been closed, do nothing
if (!port.IsOpen) return;
// Read all the data waiting in the buffer
string data = port.ReadExisting();
AppendTextBox(data + "\r\n");
//Console.WriteLine(port.ReadExisting());
}
public void AppendTextBox(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
tbReceived.Text += value;
tbReceived.SelectionStart = tbReceived.Text.Length;
tbReceived.ScrollToCaret();
tbReceived.Refresh();
}
A port_DataReceived függvény a soros porton érkező adatokat kezelő szál. Minden egyes alkalommal, mikor valami adat kerül arra a vonalra, meghívódik ez a függvénye (viszont ez nem egy sima függvény, hanem egy szál). Az AppendTextBox függvény segítségével tud a szál a szövegdobozba írni (ilyen izémizé hozzáférési problémák vannak, ha kivülről próbálunk módosítani valamit, amit belülről is lehet... ilyenkor a c# arra ügyel, hogy nehogy egyszerre több helyről módosítsuk... egész királyul meg van oldva...).
private void Form1_Load(object sender, EventArgs e)
{
foreach (string s in SerialPort.GetPortNames()) cbComPort.Items.Add(s);
for (int i = 1; i < 20;i++ ) cbPartition.Items.Add(i);
cbComPort.SelectedIndex = 0;
cbPartition.SelectedIndex = 0;
}
Itt mondjuk meg, hogy mit csináljon a program, amikor elindul. Ebben a részben lekérdezzük a rendelkezésre álló soros portokat, valamint feltöltjük a particiokat tartalmazó kombóboxokat a megfelelő értékekkel.
private void bSend_Click(object sender, EventArgs e)
{
//Start the communication
port.Write(new byte[] {0xFF }, 0, 1);
// Select the partition
int part = int.Parse(cbPartition.Text);
port.Write(new byte[] { Convert.ToByte(part) }, 0, 1);
for (int ize = 0; ize < 100000000; ize++) ;
// send the number of lines.
port.Write(tbLineNum.Text.ToString());
port.Write(new byte[] { 0x0D }, 0, 1); //Carriage return.
input = tbPreview.Text;
string[] fields = input.Split(new char[] { ' ' });
progressBar1.Maximum = fields.Length;
for (int i = 0; i < fields.Length; i++)
{
try
{
int szam = int.Parse(fields[i]);
Console.WriteLine("Szam : " + szam);
port.Write(new byte[] { Convert.ToByte(szam) }, 0, 1);
}
catch
{
Console.WriteLine("Nem szam." + fields[i] + "\n");
}
progressBar1.Value = i;
}
progressBar1.Value = 0;
}
Ez történik, amikor megnyomjuk a küldés gombot. A program tudja, milyen lépéseket kell végigjárjon, hogy ne legyen fennakadás a kommunikációban. Ezeket a lépéseket előre le kell szögezni, hogy mindkét fél ismerje. Nagyjából úgy kell elképzelni, mint a TCP protokollt. Startbit, particio választás, csomag hossza, csomag. Csomagvég karakter nincs. Csomag vége utan rögtön következik a másik csomag.
A programban még lesznek kisebb nagyobb (főként esztétikai jellegű) változtatások, viszont a motor ugyanez marad. Ideálisan alkalmazható az IK-SE programmal, ami az Inverz Kinematika V2.0 részben került bemutatásra.
A programból érkező információt értelmező és feldolgozó MicroBlaze programrészlet a következőképpen néz ki:
//====================================================
// PREMADE SEQUENCE -> INTERRUPT HANDLER FUNCTION
//====================================================
//How to use it?
//
// I. Send 255 to start the communication.
// II. Send the number of the Sequence, which you want to erase.
// III. Send the number of the parts of sequence numbers
// (if you have 49500 sequence, you send 2.)
// IV. Send the numbers, which multiplied gives the number of sequences
// (if you have 49500 sequence, you send (250 and 198) or (220 and 225)
// or something similar.)
// V. Send the sequence values. (expl: 49500 number between 0 and 255)
// END.
//Set a flag to fill the numbers from 49500 to the 0x0C7000 with 128 <- Not yet implemented
//It would be good, to fill the memory segments with 101888 value =>0xC7000 memory address
//implemented on user program side. TO send 101888 value. Approx. 18 minutes
void uart_interrupt_handler(void* addr_p)
{
//receiving premade sequences from the computer and store them in the MicronRam Memory.
Xuint8 empty;
empty = XUartLite_IsReceiveEmpty(XPAR_RS232_PORT_BASEADDR);
if (empty == FALSE )
{
buchstabe2 = XUartLite_RecvByte(XPAR_RS232_PORT_BASEADDR);
//xil_printf("Buchstabe : %d pre_seq_stage = %d\n",buchstabe2,pre_seq_stage);
if((buchstabe2==255)&&(pre_seq_stage==0))
{
pre_seq_stage=10;//START.
//xil_printf("Start receiving PWM. Send the Sequence number.\n");
}
if(pre_seq_stage == 1)//Which MemorySEQ?
{
if((buchstabe2<=19)&&(buchstabe2>0))//Limits
{
//xil_printf("Selected Sequence : %d\n",buchstabe2);
premade_sequence = (Xuint8*)XPAR_MICRON_RAM_MEM0_BASEADDR + (2+buchstabe2)*0xC7000;
pre_seq_stage = 20;
//xil_printf("Send the number of lines.\n");
}
//else xil_printf("Please select a Sequence memory between 1 and 19 (inclusive).\n");//error message.
}
if (pre_seq_stage == 2)//how many numbers in the number of sequences
{
//xil_printf("First Number = %c \n",buchstabe2);
num_num = buchstabe2;
if (buchstabe2 == 13)
{
pre_seq_stage =30;
c3=c3*18;
c3=c3/10;
////xil_printf("Vegleges szam ertek : %d\n",c3);
//xil_printf("Kuldjed a PWM ertekeket.\n");
}
else if ((buchstabe2>=48)&&(buchstabe2<=57))
{
c3=c3+(buchstabe2-48);
c3=c3*10;
//xil_printf("Szam erteke : %d\n",c3);
}
}
if(pre_seq_stage == 3)//reading the sequence values.
{
premade_sequence[counter] = buchstabe2;
//xil_printf("Received value : %d\n",buchstabe2);
//xil_printf("Saved value : %d\n",premade_sequence[counter]);
//xil_printf("Counter : %d C3 : %d\n",counter,c3);
counter = counter+1;
if(counter == c3)
{
c3=0;
pre_seq_stage = 0;
xil_printf("Vege a dalnak.\n");
}
}
if (pre_seq_stage==10) pre_seq_stage = 1;
if (pre_seq_stage==20) pre_seq_stage = 2;
if (pre_seq_stage==30) pre_seq_stage = 3;
}
}
Röviden ennyi lenne a mai bejegyzés. Remélem este írhatok valami jobbat is, mint pár forráskód.
0 megjegyzés:
Megjegyzés küldése