Пакет данных по uart

Поклонники продукции Microchip Technology Inc тусуются тут.
Ответить
Аватара пользователя
virus33
Нашел транзистор. Понюхал.
Сообщения: 175
Зарегистрирован: Пт июн 29, 2012 23:48:11

Пакет данных по uart

Сообщение virus33 »

Есть два камня связанных по uart. Первый снимает значения с АЦП, порта RD и отправляет пакет данных, который представляет собой четыре байта по uart на скорости 9600. Указывается начало пакета и его конец ввиде четырех битов соответственно. Сбор значений и отправка пакета происходит нормально. Но прием не работает вообще и никак. Камни используютя для передачи 16F877и для приема 16F628a.
Внимание! Код хоть и ламерский но много!
Приемник:
Спойлер

Код: Выделить всё


#include <pic.h>

__CONFIG(HS & WDTDIS & PWRTDIS & BORDIS & LVPDIS & UNPROTECT); //биты камня(они же фьюзы в avr)


//Пакет данных
unsigned char StartByte;			//Первый байт
unsigned char ADCbyte;				//Второй байт
unsigned char ServoByte;			//Третий байт
unsigned char StopByte;				//Четвертый байт
unsigned char NumOfByte;			//Порядок байтов
//Пакет данных

//Сервопривод
static	volatile unsigned int  num         @ 0x26; // ширина импульса
static	volatile unsigned char numL        @ 0x26; // ширина импульса младший
static	volatile unsigned char numH        @ 0x27; // ширина импульса старший
short int delay;
short int dTime;
//Сервопривод

unsigned char error;
unsigned char ErrorMode;
unsigned char Tbyte;
unsigned char temp;

void init (void){
CMCON = 0x07;       	//Отключаем компараторы.
TRISA = 0b00000000; 	//Порт А - на выход.
TRISB = 0b00000110;		//Порт В - на выход, пины RB3/RB2 которые принадлежат RX/TX
PORTA = 0;          	//далее - очищаем порты.
PORTB = 0;				
//      UART
// TXSTA : CSRC TX9  TXEN SYNC --- BRGH   TRMT   TX9D
TXSTA=0b00100000;		        // Asynch,8bits,tx enb

// RCSTA : SPEN RX9  SREN CREN ADEN FERR   OERR   RX9D
RCSTA=0b10010000;		        // Cont receive enb	

SPBRG=32;	//	asinhron  BRGH=0 ->32;BRGH=1 ->129 for 9600
OPTION = 0b10000111;	//Конфигурация переферии по умолчанию, предделитель таймера 0 на 256
INTCON = 0b11100000;	//Конфигурация прерываний
T0IF = 0;				//Сбрасываем флаг таймера 0
CCP1CON = 0b00001100;	//Настройка ШИМ канала RC2
CCPR1L = 0b0000000;		//Начальная скважность импульсов 0%
T2CON = 0b00000101;		//Таймер 2 - включен, 1:4 
TMR2 = 0;				//Таймер 2 - стартуем с 0
PR2 = 0xFF; 			//Значение регистра периода таймера 2 для ШИМ генерации
T1CON  = 0b00010001;  //  Настройка TMR1
TMR1IE = 1;
TMR1IF = 0;
//////////////////////////////////////////////////////////////////////
// 						Регистр настроек OPTION						//
//RBPU   = 1;		//подтягивающие резисторы выкл			бит 7	//
//INTEDG = 0;		//прерывания по заднему фронту сигнала	бит 6	//
//T0CS   = 0;		//внутренний тактовый сигнал таймера 0	бит 5	//
//T0SE   = 0;		//приращение по переднему фронту TMR0	бит 4	//
//PSA    = 0;		//предделитель включен перед TMR0		бит 3	//
//PS2    = 1;		//установка								бит 2	//
//PS1    = 1;		//коэффициента							бит 1	//
//PS0    = 1;		//предделителя TMR0	на 256				бит 0	//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//						Регистр прерываний INTCON					//
//GIE  = 1;			//разрешаем глобальные прерывания		бит 7	//
//PEIE = 1;			//разрешаем прерывания периферии		бит 6	//
//T0IE = 1;			//запрещаем прерывания по таймеру 0		бит 5	//
//INTE = 0;			//запрещаем внешние прерывания			бит 4	//
//RBIE = 0;			//запрещаем прерывания по порту В		бит 3	//
//T0IF = 0;			//очищаем флаг таймера 0 				бит 2	//
//INTF = 0;			//очищаем флаг внешнего прерывания		бит 1	//
//RBIF = 0;			//очищаем флаг прерывания на порту В	бит 0	//
//////////////////////////////////////////////////////////////////////
num = 61785;
NumOfByte = 0;
}

//	UART
unsigned char getch_Usart(void)									//	Получение байта.
{
	while(!RCIF)												//	Устанавливается, когда регистр не пуст.
		continue;
	return RCREG;
}

void send_Usart(unsigned char c) 								//	Отправка байта.
{
	while(TXIF!=1)												//	Устанавливается, когда регистр свободен.
	{}
	TXREG = c;	
}
//	-UART

void SafeMode(void)												//Выполняем "Safe Mode".
{
CCPR1H = 0;
delay = 128;
RB7 = 0;
RB6 = 0;
RB5 = 0;
RB4 = 0;
RA3 = 0;
RA2 = 1;
RA1 = 0;
RA0 = 0;
error = 1;														//Включаем сигнал об обрыве связи.
}

void LoadPacket (void)											//Загружаем данные пакета.
{
if (NumOfByte == 4 ){
					error = 0;									//Отключаем сигнал об обрыве связи.
					NumOfByte = 0;
					CCPR1H = ADCbyte;
					delay = ServoByte;
					StartByte &= 0b00001111;
					PORTB = StartByte;
					StopByte &= 0b11110000;
					PORTA = StopByte;
					}
}

void ReceiveSetting()
{
}

void StartConfig()
{
}

void main (void)
{
init();															//Проходим конфигурацию.
StartConfig();													//Загружаем начальные значения из EEPROM.
while(1){
		if(RCIF){
				TMR0 = 0;										//Обнуляем таймер ожидания пакета.
				Tbyte = getch_Usart();
				temp = Tbyte;
				temp &= 0b11110000;								//Проверяем, первый ли это байт пакета.
				if (temp == 0b11010000)	{
										NumOfByte = 1;			//Пришел 1й байт?
										StartByte = Tbyte;
										Tbyte = 0;
										TMR0 = 0;				//
										} else	{				//Не совпадает со стартовым?
												if (NumOfByte == 1 ){						//Пришел второй байт?
																	NumOfByte = 2;
																	ADCbyte = Tbyte;
																	goto exit;				//Выходим из условия и ждем 3й байт.
																	}
												if (NumOfByte == 2 ){
																	NumOfByte = 3;			//Пришел третий байт?
																	ServoByte = Tbyte;
																	goto exit;				//Выходим из условия и ждем 4й байт.
																	}
												if (NumOfByte == 3 ){
																	temp = Tbyte;
																	temp &= 0b00001111;
																	if (temp == 0b00001101)	{					//Пришел стоп байт?
																							NumOfByte = 4;
																							StopByte = Tbyte;
																							LoadPacket();		//Пакет принят.
																							} else	{
																							SafeMode();			//Пакет не принят.
																							}		
																	goto exit;				//Выходим из условия.
																	}
												exit:
												while (1 < 2) 	{
																asm ("NOP"); 
																}					
												}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				if (temp == 0b10110000)	{
										NumOfByte = 1;			//Пришел 1й байт?
										StartByte = Tbyte;
										Tbyte = 0;
										TMR0 = 0;				//
										} else	{				//Не совпадает со стартовым?
												if (NumOfByte == 1 ){						//Пришел второй байт?
																	NumOfByte = 2;
																	ADCbyte = Tbyte;
																	goto wait;				//Выходим из условия и ждем 3й байт.
																	}
												if (NumOfByte == 2 ){
																	NumOfByte = 3;			//Пришел третий байт?
																	ServoByte = Tbyte;
																	goto wait;				//Выходим из условия и ждем 4й байт.
																	}
												if (NumOfByte == 3 ){
																	temp = Tbyte;
																	temp &= 0b00001111;
																	if (temp == 0b00001011)	{					//Пришел стоп байт?
																							NumOfByte = 4;
																							StopByte = Tbyte;
																							LoadPacket();		//Пакет принят.
																							} else	{
																							SafeMode();			//Пакет не принят.
																							}		
																	goto wait;				//Выходим из условия.
																	}
												wait:
												while (1 < 2) 	{
																asm ("NOP"); 
																}					
												}		
				}
						
		}	
}

void interrupt pwm_int(void)									// Общая процедура прерывания.
{
if (T0IF == 1)
	{
	if (error == 1)	{
					ErrorMode = ErrorMode + 1;
					if (ErrorMode == 153)	{
											ErrorMode = 0;
											RA2 = ~RA2;
											}
					}
	SafeMode();													//Пакет данных не получен.
	T0IF = 0;
	}

if (TMR1IF)	{
			T0IE = 0;											//Вырубаем первый таймер чтоб не сифонил по чем зря.
			TMR1IF=0;     										// Сбрасываем флаг о его переполнении.
			if (num < 61000){									//Ширина импульса.
							delay = delay*10;
							num = 61785+delay;
							TMR1H = numH;
							TMR1L = numL;
							RB3 = 1;
							} else {							//50гц.
									RB3 = 0;
									dTime = 65535 - num;
									num = 65535 - (50000 - dTime);
									TMR1H = numH;
									TMR1L = numL;
									}
			T0IE = 1;											//Врубаем первый таймер.
			}

}
Передатчик:
Спойлер

Код: Выделить всё


#include <pic.h>

__CONFIG(HS & WDTDIS & PWRTDIS & BORDIS & LVPDIS & UNPROTECT); //биты камня(они же фьюзы в avr)

#define temp		RB0				// temporary key for testing delay's

unsigned char StartByte;			//Первый байт
unsigned char ADCbyte;				//Второй байт
unsigned char ServoByte;			//Третий байт
unsigned char StopByte;				//Четвертый байт
unsigned char x;
short int delay;

void init (void){
CMCON = 0x07;       	//Отключаем компараторы
TRISA = 0b00001011; 	//Порт А - на вход, три канала АЦП RA0,RA1,RA3
TRISB  = 0b00000000;	//
TRISC = 0b11000000; 	//RC6, RC7, которые принадлежат uart
TRISD = 0b11111111;
TRISE = 0b00000000;
PORTA = 0;          	//далее - очищаем порты
PORTB = 0;				
PORTC = 0;
PORTD = 0;
PORTE = 0;
//      76543210
// TXSTA : CSRC TX9  TXEN SYNC --- BRGH   TRMT   TX9D
TXSTA=0b00100000;		        // Asynch,8bits,tx enb

// RCSTA : SPEN RX9  SREN CREN ADEN FERR   OERR   RX9D
RCSTA=0b10010000;		        // Cont receive enb	

SPBRG=32;	//	asinhron  BRGH=0 ->32;BRGH=1 ->129 for 9600
OPTION = 0b10000111;	//Конфигурация переферии по умолчанию, предделитель таймера 0 на 128
INTCON = 0b01100000;	//Конфигурация прерываний
ADCON0 = 0b00000001;	//Конфигурация АЦП
ADCON1 = 0b00000100;
//////////////////////////////////////////////////////////////////////
// 						Регистр настроек OPTION						//
//RBPU   = 1;		//подтягивающие резисторы выкл			бит 7	//
//INTEDG = 0;		//прерывания по заднему фронту сигнала	бит 6	//
//T0CS   = 0;		//внутренний тактовый сигнал таймера 0	бит 5	//
//T0SE   = 0;		//приращение по переднему фронту TMR0	бит 4	//
//PSA    = 0;		//предделитель включен перед TMR0		бит 3	//
//PS2    = 1;		//установка								бит 2	//
//PS1    = 1;		//коэффициента							бит 1	//
//PS0    = 0;		//предделителя TMR0	на 256				бит 0	//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//						Регистр прерываний INTCON					//
//GIE  = 1;			//разрешаем глобальные прерывания		бит 7	//
//PEIE = 1;			//разрешаем прерывания периферии		бит 6	//
//T0IE = 1;			//разрешаем прерывания по таймеру 0		бит 5	//
//INTE = 0;			//запрещаем внешние прерывания			бит 4	//
//RBIE = 0;			//запрещаем прерывания по порту В		бит 3	//
//T0IF = 0;			//очищаем флаг таймера 0 				бит 2	//
//INTF = 0;			//очищаем флаг внешнего прерывания		бит 1	//
//RBIF = 0;			//очищаем флаг прерывания на порту В	бит 0	//
//////////////////////////////////////////////////////////////////////
}

//	UART
unsigned char getch_Usart(void)//	Получение байта
{
	while(!RCIF)	//	Устанавливается, когда регистр не пуст.
		continue;
	return RCREG;
}

void send_Usart(unsigned char c) //	Отправка байта
{
	while(TXIF!=1)	//	Устанавливается, когда регистр свободен
	{}
	TXREG = c;	
}
//	-UART

void main (void)
{
init();														//проходим конфигурацию
while(1)	{
			temp = 1;
			StartByte = 0b11010000;
			StopByte = 0b00001101;

			ADCON0 = 0b00000001;							// обрабатываем значение оси Z(акселерометр), канал ацп RA1
			delay = 0;
			while (delay < 10)	{							//Задержка АЦП
								delay = delay + 1;
								}
			ADGO = 1;
			while (ADGO == 1)	{
								asm("NOP");
								}			
			ADCbyte = ADRESH;								//Значения из АЦП отправляем в переменную Z	

			ADCON0 = 0b00001001;							// обрабатываем значение оси X(вперед - назад), канал ацп RA2
			delay = 0;
			while (delay < 10)	{							//Задержка АЦП
								delay = delay + 1;
								}
			ADGO = 1;
			while (ADGO == 1)	{
								asm("NOP");
								}			
			x = ADRESH;										//Значения из АЦП отправляем в переменную X
			if (x < 130)	{								//Устанавливаем ноль на центре манипулятора Х(+/- 2 значения погрешности)
							if (x > 126)	{
											StopByte &= 0b00111111; //Вперед и назад выкл.
											}
							} 
			if (x > 130 )	{
							StopByte |= 0b10000000;					//Вперед
							}
			if (x < 126 )	{
							StopByte |= 0b01000000;					//Назад
							}

			ADCON0 = 0b00011001;							// обрабатываем значение оси Y(импульс сервопривода), канал ацп RA3
			delay = 0;
			while (delay < 10)	{							//Задержка АЦП
								delay = delay + 1;
								}
			ADGO = 1;
			while (ADGO == 1)	{
								asm("NOP");
								}			
			ServoByte = ADRESH;								//Значения из АЦП отправляем в переменную ServoByte

			if (RD0 == 1)	{
							StartByte |= 0b00000001;
							}
			if (RD1 == 1)	{
							StartByte |= 0b00000010;
							}
			if (RD2 == 1)	{
							StartByte |= 0b00000100;
							}
			if (RD3 == 1)	{
							StartByte |= 0b00001000;
							}
			if (RD4 == 1)	{
							StopByte |= 0b00010000;
							}
			if (RD5 == 1)	{
							StopByte |= 0b00100000;
							}				
			send_Usart(StartByte);			//Первый байт
			send_Usart(ADCbyte);			//Второй байт
			send_Usart(ServoByte);			//Третий байт
			send_Usart(StopByte);			//Второй байт
////////////////////////////////////////////////////////////////////////////
			temp = 0;
			delay = 0;
			while (delay < 150)	{							//Мертвое время проца
								delay = delay + 1;
								}
			}	
}

void interrupt pwm_int(void)	// общая процедура прерывания
{
if (T0IF == 1)
	{
	TMR0 = 60;					//10 мсек на тик
	T0IE = 0;					//Отключаем таймер
	T0IF = 0;					//Сбрасываем флаг
	T0IE = 1;					//Включаем таймер
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////
if (TMR2IF == 1)				//таймер 2
	{									
	TMR2IF = 0;					//сброс флага
	}

}
Суть следующая. При приеме проверяется флаг RCIF, если присутствует, читаем RCREG и смотрим что нам за байт пришел. Если пакет не пришел в указанное время то включаем так назваемый Safe Mode(по сути, сбрасываем данные на дефолт). В даташите как бы указано, что при чтении RCREG флаг RCIF сбрасывается аппаратно. Но чет код вообще нифига не пашет(. Прерывание не использую т.к. там своих прерываний хватает, еще сдесь вырезал функции записи EEPROM, опроса датчиков, отправки данных другим абонентам etc.
Какие у вас есть мысли?
Вложения
code.rar
(4.78 КБ) 172 скачивания
Реклама
Аватара пользователя
WandererSc
Друг Кота
Сообщения: 4077
Зарегистрирован: Вс мар 22, 2009 17:31:41

Re: Пакет данных по uart

Сообщение WandererSc »

В даташите как бы указано, что при чтении RCREG флаг RCIF сбрасывается аппаратно.
Да, сбрасывается.
Ну а с кодом долго разбираться, но там есть строки, которые как-то не хорошо выглядят.
Например

Код: Выделить всё

while(TXIF!=1)												//	Устанавливается, когда регистр свободен.
Лучше заменить на

Код: Выделить всё

while (!TRMT); // ждет пока регистр не освободится

или вот почему код большой

Код: Выделить всё

RB7 = 0;
RB6 = 0;
RB5 = 0;
RB4 = 0;
RA3 = 0;
RA2 = 1;
RA1 = 0;
RA0 = 0;
можно заменить на

Код: Выделить всё

PORTA  = 0b00000100;
Ну и гвоздь программы

Код: Выделить всё

												while (1 < 2) 	{
																asm ("NOP"); 
																}	
Это то что повесит контроллер навсегда :facepalm:
Последний раз редактировалось Аlex Пт окт 17, 2014 08:45:33, всего редактировалось 1 раз.
Причина: -
Раз reset, два reset - полyчи на диске bad !
Тpанзистоp p-n-p. Plug-n-Play ?
У кого что сбоит, тот о том и говорит.
Реклама
Аватара пользователя
virus33
Нашел транзистор. Понюхал.
Сообщения: 175
Зарегистрирован: Пт июн 29, 2012 23:48:11

Re: Пакет данных по uart

Сообщение virus33 »

Как говорится, если код выкладываешь на форум, выкладывай его полностью... хотя там реально кода раза в два больше.
А гвоздь программы не увидел, да, глупость написал. работать от этого как надо код не стал, но, уже легче, хотя бы при обрыве связи включался т.н. SafeMode. И кстати еще один гвоздь программы:

Код: Выделить всё

	StartByte &= 0b00001111;
	PORTB = StartByte;
	StopByte &= 0b11110000;
	PORTA = StopByte;
Вроде бы ненужные единички сбрасываю в ноль, а затем нули записываю в весь порт, от чего не работает шим. (вывод должен быть только на RA0 - RA3 и RB4 - RB7)
Ответить

Вернуться в «PIC»