Asi ani neskusaj
Pod prerusenim mas zase nejake casove slucky, ktore Ti este moze prekladac zoptimalizovat a pripadne aj z programu vyhodit (dovody som pisal vyssie).
Okrem toho, ako vidim na RX do MCU (teda TX zo Zigbee modulu) mas privedeny /wr a nie vstup od citaca casovaca.
Musis si byt 110% isty, co oznacenie TX a RX na Zigbee znamena. Normalne by to malo znamenat, ze do RX na module ide signal TX z MCU a signal z TX na module ma ist do RX na MCU.
Nerobim s x51, tak ti neviem napisat program s presnym oznacenim registorom v Tvojom MCU, ale princip je rovnaky.
- TX z modulu pripoj napr na vstup T0.
potom si prepis nasledovny algoritmus. Je to pre ATmega. Netestujem extra start bit, preto je tam na zaciatku 1.5 nasobok Bd
SIGNAL (COM5_SIG_TEST_START_BITU) - funkcia, ktora sa zavola po preteceni casovaca, ked je nastaveny v mode pocitadla vst impulzov a ma nastavenu predvolbu na 0xff
toto su vsetko makra, ktore si musis ty napisat podla svojho, ich vyznam je jasny z nazvov
COM5_ZAKAZ_PRERUSENIA_OVERFLOW_TIMER;
COM5_SET_TIMER_RX_TX_BIT; // zapni prijem od compare match
COM5_POVOLENIE_PRERUSENIA_COMAPRE_MATCH;
SIGNAL (COM5_SIG_TIMER_RX_TX_BIT) - funkcia, ktora sa zavola, ked pride prerusenie od compare match
// Definicia LOCALnych funkcii
// identifikacia start bitu, prisla dobezna hrana signalu
SIGNAL (COM5_SIG_TEST_START_BITU)
{
// nastav hodnotu compare match na 1.5 nasobok bitovej rychlosti a prerusenie od compare match
SET(sw_status,ROZPRACOVANY_PRIJEM);
COM5_PRAC_POCITADLO = 0x00;// prednastavenie hodnoty TCNT tak, aby pri najblizsiemu compare match doslo k preruseniu
COM5_COMPAR_REGISTER = sw_predvolba_pre_1_5nasobok_bitu;
sw_udr_prac = 0;
sw_pocitadlo_bitov = 0;
COM5_ZAKAZ_PRERUSENIA_OVERFLOW_TIMER;
COM5_SET_TIMER_RX_TX_BIT; // zapni prijem od compare match
COM5_POVOLENIE_PRERUSENIA_COMAPRE_MATCH;
return;
}
SIGNAL (COM5_SIG_TIMER_RX_TX_BIT)
{
uint8_t prac;
COM5_COMPAR_REGISTER = sw_predvolba_pre_1nasobok_bitu;
sw_pocitadlo_bitov++;
// bezi prijem
if TST(sw_status,ROZPRACOVANY_PRIJEM) {
// test stop bitu
if (sw_pocitadlo_bitov > 8) {
if (GET_RX5) {
sw_udr = sw_udr_prac;
// ****************** zrusenie prerusenia po prijati bajtu ****************
RES(sw_status,ROZPRACOVANY_PRIJEM);
COM5_ZAKAZ_PRERUSENIA_COMAPRE_MATCH;
COM5_PRAC_POCITADLO = COM5_MAX_HODNOTA_PRAC_POCITADLA;// prednastavenie hodnoty TCNT tak, aby pri najblizsej dobeznej hrane prislo k preruseniu
COM5_SET_TEST_START_BITU; // zapni prijem
COM5_RES_INT_FLAG;
COM5_POVOLENIE_PRERUSENIA_OVERFLOW_TIMER;
POVOLENIE_PRERUSENIA;
// ************************************************************************
// inicializacia funkcie PAUSE, lebo bolo nieco prijate
timer_com5.timer = COM5_TIMEOUT_RX;
prg_tb_timer(TB_5ms, TIMER_INIT, (TIMER_STRUCT * ) &timer_com5);
#if (COM5_ECHO == TRUE)
sprava_prijata = TRUE;
mem[cnt_mem_max] = sw_udr;
if (cnt_mem_max < (MAX_MEM - 1)) {
cnt_mem_max++;
}
RES(sw_status,ROZPRACOVANY_PRIJEM);
RES(sw_status,ROZPRACOVANE_VYSIELANIE);
COM5_ZAKAZ_PRERUSENIA_COMAPRE_MATCH;
COM5_PRAC_POCITADLO = COM5_MAX_HODNOTA_PRAC_POCITADLA;// prednastavenie hodnoty TCNT tak, aby pri najblizsej dobeznej hrane prislo k preruseniu
COM5_SET_TEST_START_BITU; // zapni prijem
COM5_POVOLENIE_PRERUSENIA_OVERFLOW_TIMER;
return;
// priprav nacitanie dalsieho bajtu
#else
com5_struct.pracovny_bajt = sw_udr;
prac = prg_prijaty_bajt((COM_STRUCT *)&com5_struct);
if (prac == COM_VYPNI_PRIJEM) {
// ak bol pri novej sprave este stale zablokovany box, iniciuj ho
SET(com5_struct.status,SPRACUJ_PROTOKOL);
RES(sw_status,ROZPRACOVANY_PRIJEM);
COM5_ZAKAZ_PRERUSENIA_COMAPRE_MATCH;
return;
}
RES(sw_status,ROZPRACOVANY_PRIJEM);
RES(sw_status,ROZPRACOVANE_VYSIELANIE);
COM5_ZAKAZ_PRERUSENIA_COMAPRE_MATCH;
COM5_PRAC_POCITADLO = COM5_MAX_HODNOTA_PRAC_POCITADLA;// prednastavenie hodnoty TCNT tak, aby pri najblizsej dobeznej hrane prislo k preruseniu
COM5_SET_TEST_START_BITU; // zapni prijem
COM5_POVOLENIE_PRERUSENIA_OVERFLOW_TIMER;
return;
#endif
}
// nebol stop bit
else prg_com5(COM_ZAPNI_PRIJEM, 0);
}
else {
sw_udr_prac >>= 1; // rotacia do prava
if (GET_RX5) {
sw_udr_prac |= 0x80;
}
// skratenie casu testu stop bitu
if (sw_pocitadlo_bitov == 8) COM5_COMPAR_REGISTER = sw_predvolba_pre_0_8nasobok_bitu;
}
return;
}
if TST(sw_status,ROZPRACOVANE_VYSIELANIE) {
// generovanie start bitu
if (sw_pocitadlo_bitov == 1) {
#if (COM5_ECHO == TRUE)
if (cnt_mem == cnt_mem_max) { // ukonci vysielanie
prg_com5(COM_ZAPNI_PRIJEM, 0);
return;
}
else {
if (cnt_mem == 0) sw_udr = 's';
else sw_udr = mem[cnt_mem];
if (cnt_mem < cnt_mem_max) cnt_mem++;
}
#else
sw_udr = prg_vyslany_bajt((COM_STRUCT *)&com5_struct);
#endif
if TST(com5_struct.setup,PREPINAJ_SMER) { // je rezim RS485
COM5_SMER_RS485_RX;
}
RES_TX5;
}
else {
if (sw_pocitadlo_bitov < 10) {
if (sw_udr & 0x01) SET_TX5;
else RES_TX5;
sw_udr >>= 1;
}
// generuj 3x stop bit
if (sw_pocitadlo_bitov == 10) {
SET_TX5;
}
// otestuj, ci treba este vysielat
if (sw_pocitadlo_bitov == 13) {
if TST(com5_struct.setup,PREPINAJ_SMER) { // je rezim RS485
COM5_SMER_RS485_RX;
}
sw_pocitadlo_bitov = 0;
#if (!(COM5_ECHO == TRUE))
// ak sa uz nema nic odvysielat, potom prepni UART na prijem
if (!(TST(com5_struct.status,JE_VYSIELANIE))) {
prg_com5(COM_ZAPNI_PRIJEM, 0);
}
#endif
}
}
return;
}
}
Ale z toho asi velmi mudry nebudes , to bolo iba na ukazku ako fragment z realnej sw komunikacnej rutiny. Nie je tam uplne vsetko a o tom kode ani nemusime polemizovat. Uviedol som to iba ako dokaz, ze viem o com pisem.
Takze este raz mnemotechnicky. Neviem, ci ma x51 compare match, budem teda pisat algoritmus ako by bolo prerusenie iba od pretecenia casovaca. Predpokladam, ze sprava je ukoncena znakom 0x0d
#define FALSE 0x00
#define TRUE 0xff
#define KONCOVY_ZNAK 0x0d
#define MAX_POCET_BAJTOV 100
uint8_t prijaty_bajt, cnt_pom, bufer[MAX_POCET_BAJTOV], aktual_index, sprava_ukoncena = FALSE;
int main(void)
{
fn_inicializacia_prijmu_bajtu();
aktual_index = 0;
// hlavna slucka, tusi rob co chces
while(1) {
if (sprava_ukoncena == TRUE) {
fn_spracuj_protokol();
}
// ak neprisla sprava, kludne si volaj do kolecka svoje dalsie funkcie, napr na spracovanie displaya a tak podobne. Len sa cas od casu pozri, ci uz nahodou nebola prijata cela sprava.
}
}
void fn_prerusenie_od_pretecenia(void)
{
// ak bola sprava ukoncena a je zle osetrene vypnutie prerusenia, tak z funkcie hned vyskoc
if (sprava_ukoncena == TRUE) return;
// normalna cinnost rutiny
if (cnt_pom == 0) {
- nastav T0 ako casovac
- nastav do T0 predvolbu tak, aby sa po uplynuti casu 0.5Bd vyvolalo prerusenie
}
// ak cakas start bit
if (cnt_pom == 1) {
// a na pine T0 je naozaj nula, potom pokracuj
if (!(PORT_P3 & (1<<pin_T0))) {
- nastav do T0 predvolbu tak, aby sa po uplynuti casu 1 Bd vyvolalo prerusenie
}
// nejednalo sa o start bit, ale asi o nejaky sum
else {
fn_inicializacia_prijmu_bajtu();
return;
}
}
if (cnt_pom > 1) && (cnt_pom <= 9) {
prijaty_bajt = prijaty_bajt<<1;
if (PORT_P3 & (1<<pin_T0))) {
prijaty_bajt = prijaty_bajt + 0x01;
}
// otestuj stop bit
if (cnt_pom == 10) {
if (PORT_P3 & (1<<pin_T0))) {
bufer[aktual_index] = prijaty_bajt;
if (prijaty_bajt !=KONCOVY_ZNAK) {
aktual_index++;
// ochrana proti preteceniu bufera
if (aktual_index >=MAX_POCET_BAJTOV) aktual_index = 0;
}
else {
// v premennej aktual_index mas pocet priajtych bajtov
sprava_ukoncena = TRUE;
- zakaz prerusenia od T0
return;
}
}
// neprisiel stop bit
else {
fn_inicializacia_prijmu_bajtu();
return;
}
}
cnt_pom++;
}
void fn_inicializacia_prijmu_bajtu(void)
{
- nastav pin T0 ako vstupny
- nastav do predvolby T0 0xff
- nastav prerusenie od pretecenia T0
prijaty_bajt = 0;
cnt_pom = 0;
}
void fn_spracuj_protokol(void)
{
// co len chces
// ....
// koniec co len chces
sprava_ukoncena = FALSE;
fn_inicializacia_prijmu_bajtu();
aktual_index = 0;
}
Dufam, ze som v druhom kode nenarobil nejake principialne chyby, treba to skontrolovat. Hlavne si vsimni, ze nikde ziadne cakacie slucky
Obdobne naprogramujes i vysielanie. Na zaciatok prerusovacej rutiny si este hodis podmienku ci sa sprava prijima, alebo vysiela. Pri vysielani vyuzivas iba prerusenie od casovaca v periode casu 1Bd.
Prajem vela uspechov a daj vediet ze co a ako.