LINUX.ORG.RU

[C-51] Поделитесь примерами кода


0

0

Приперло по работе написать довольно сложную программу для контроллера с архитектурой 8051, для чего нужно использовать язык С-51. А у меня знакомство с ним ограничилось только выставлением на ножку единицы или нуля в зависимости от числа.

Хотелось бы поглядеть примеры более сложных программ, с использованием больших возможностей контроллера (регистров, флагов и т.д.).

З.Ы. Надо будет заставить его работать по юсб с компутером. Все вроде как не так уж сложно при конфигурировании, читаешь даташит на контроллер, прописываешь нужный флагу в нужные регистры и т.д., но все равно хотелось бы глянуть сложные рпограммы на С-51, чтобы уж чтоно не оплошать =) Гуголь особых результатов не выдал...

★★★★★

Так там ведь тот же С, отличие лишь в регистрах специального назначения. Для 8051, правда, давно уже ничего не делал, но для PIC16 могу привести рабочий пример:

#include	<pic16f873a.h>
#include "signals.h"
#define BUFSIZE	95
//#define CLRWDT	_asm clrwdt _endasm;
typedef unsigned int word;
word at 0x2007 CONFIG = 0x3F72; // для WDT: 0x3F76
unsigned char
	cmd,		// полученная команда
	d_H, d_L,	// старший и младший байты двухбайтной посылки
	T1H, T1L,	// значения регистров счетчика таймера 1
	mC_addr;	// физ. адрес контроллера (константа, устанавливается функцией init)

unsigned char SPI_buf[BUFSIZE], SPI_cntr;

void send9bit(unsigned char something){
	unsigned char tmp;
	something &= 0x1F; // сброс старших трех бит (там будет адрес)
	tmp = mC_addr | something;
	TXEN = 1; // готов к передаче
	TX9D = 0; // 0 - передает контроллер
	TXREG = tmp;	// послать команду
}

unsigned char get9bit(){
	unsigned char err1, err2, flag9bit, tmp;
	while(!RCIF);
	flag9bit = RX9D;
	err1 = FERR; err2 = OERR; // считать 9-й бит и ошибки
	cmd = RCREG; // очистить буфер данных
	RX9D = 0;
	if(err1 == 1)
		return NO_STOP_BIT;
	if(err2 == 1){
		CREN = 0; CREN = 1; // сбросить флаг ошибки
		return STACK_OVERFLOW;
	}
	if(flag9bit) return TWOBYTE; // данные - часть двухбайтной посылки (неизвестно еще чьей :) )
	tmp = cmd & 0xE0; // выделение адреса из команды
	cmd &= 0x1F; // обнуление адресных битов
	if(tmp != mC_addr) return ERR_CMD; // если адресован чужому
	send9bit(cmd); // Эхо принятой команды
	return OK;
}

void sendword(unsigned char data_H, unsigned char data_L){
	RCIE = 0; // disable USART in interrupt
	TMR1IE = 0;
	TXEN = 1;
	TX9D = 1;
	TXREG = data_H;
	while(!TRMT);
	TXEN = 1;
	TX9D = 1;
	TXREG = data_L;
	RCIE = 1;
	TMR1IE = 1;
}

unsigned char getword(){
	unsigned char ret = 0;
	RCIE = 0; // disable USART in interrupt
	TMR1IE = 0;
	if(ten_times_read()){
		d_H = cmd;
		if(ten_times_read()){
			d_L = cmd;
			ret = 1;}} // если оба байта считали правильно
	TMR1IE = 1;
	RCIE = 1; // enable USART in interrupt
	return ret;
}

unsigned char ten_times_read(){ // 10 попыток чтения для двухбайтного приема
	unsigned char i=0;
	do i++;
	while(get9bit() != TWOBYTE && i < 10);
	if(i > 9){send9bit(ERR_CMD); return 0;}
	send9bit(OK);
	return 1; 
}

void init(){ // инициализация
// Настройка USART'a
// TXSTA: | CSRC | TX9 | TXEN | SYNC | N/A | BRGH | TRMT | TX9D |
	TXSTA = 0x66; // (11000110): master, 9-ти битный ввод/вывод, async, hi-speed, ready
// SPBRG - скорость передачи
	SPBRG = 25; // 9.6 кб/с
// RCSTA: | SPEN | RX9 | SREN | CREN | ADDEN | FERR | OERR | RX9D |
	RCSTA = 0xD0; // ( 11010000): enable, 9bit, continuous mode
// настройка портов:
	PORTA = 0; // 6-ти битный аналогово/цифровой порт (0..5 биты)
// ADCON1: | ADFM | N/A | N/A | N/A | PCFG3 | PCFG2 | PCFG1 | PCFG0 |
	ADCON1 = 0x06; // Аналогово/цифровой порт работает в полностью цифровом режиме
	TRISA = 0; // направление порт А (1-вход, 0-выход) 
	TRISB = 0xff; //           --/ B /--
// OPTION_REG: | !RBPU | INTEDG | TOCS | TOSE | PSA | PS2 | PS1 | PS0 |
	OPTION_REG = 0x7f; /* (01111111) 0 - подключение подтяжек на порт B (уст. лог. 1),
				прерывание по нарастающему фронту RB0,
				таймер 0 работает по сигналу с RA4
				таймер 0 увеличивается при спаде сигнала на RA4
				предделитель подключен к сторожевому таймеру
				режим prescaler:  1:128 */ 
	TRISC = 0xC0; // (11000000) - 0..5 биты как выходы
	INTCON = 0; // отключить все прерывания
	T1CON = 0;
// PIE1: | PSPIE | ADIE | RCIE | TXIE | SSPIE | CCP1IE | TMR2IE | TMR1IE |
	PIE1 = 0x20; // (00100000): enable USART(in)
// PIE2: все N/A, кроме EEIE (PIE2.4)
	PIE2 = 0; //                & disable other int.s
	PORTB = 0;
// INTCON: | GIE | PEIE | T0IE | INTE | RBIE | T0IF | INTF | RBIF |
	INTCON = 0xC0; // (1100000) - включить глобальные прерывания, прерывания по периферии
	PORTC = 0; // без напряжения
	PORTA = 0xF; // (00001111)
// получение адреса
	mC_addr = PORTB; // физический адрес устройства
	mC_addr &= 0xE0; // выделение физического адреса
	SSPEN = 0; SSPIE = 1;
	SPI_cntr = 0;
}

void timer1set(){ // установка таймера
	T1CON = 0; // выключить таймер
	TMR1IF = 0; // сбросить флаг прерывания
	TMR1IE = 1; // разр/запр прерывание
	TMR1H = T1H = d_H;
	TMR1L = T1L = d_L;
// T1CON: | - | - | T1CPS1 | T1CPS0 | T1OSCEN | T1SYNC | TMR1CS | TMR1ON |
	T1CON = 0x31; // (00110001) - включить таймер 1, предделитель на 1/8 (250 кГц)
} 

void timer1int(){ // обработка прерываний первого таймера
	T1CON = 0;
	TMR1H = T1H; TMR1L = T1L; 
//	send9bit(TEST);
	T1CON = 0x31; // снова запускаем таймер
}

void SPI_int(){ //	в пассивном режиме принимаемые данные сохраняются в
// 					буфер, при заполнении буфера он отсылается на ПК
	unsigned char i;
	if(SSPOV == 1) // ошибка переполнения буфера
		return;
	if(BF == 0) return; // буфер не заполнен
	SSPIE = 0;
	TMR1IE = 0;
	RCIE = 0;
	SPI_buf[SPI_cntr++] = SSPBUF;
	if(SPI_cntr == BUFSIZE){
		for(i = 0; i < BUFSIZE; i++){
			TXEN = 1;
			TXREG = SPI_buf[i]; 
			while(!TRMT);
		}
		SPI_cntr = 0;
	}
	RCIE = 1;
	TMR1IE = 1;
	SSPIF = 0;
	SSPIE = 1;
}

void write_SPI(unsigned char byte){
	SSPBUF = byte;
	while(!SSPIF); // ждем окончания передачи
	if(SSPOV == 1) // ошибка переполнения буфера
		return;
	SSPIE = 0;
	RCIE = 0;
	TMR1IE = 0;
	TXEN = 1;
	TXREG = SSPBUF; // отправляем полученный байт
	while(!TRMT);
	RCIE = 1;
	TMR1IE = 1;
	SSPIF = 0;
	SSPIE = 1;
}

void show_spi(){
	unsigned char i;
	SSPIE = 0;
	RCIE = 0;
	TMR1IE = 0;
	TXEN = 1;
	TXREG = SPI_cntr;
	while(!TRMT);
	if(SPI_cntr > 0)
	for(i = 0; i < SPI_cntr; i++){
		TXEN = 1;
		TXREG = SPI_buf[i]; 
		while(!TRMT);
	}
	SPI_cntr = 0;
	TMR1IE = 1;
	BF = 0;
	SSPIF = 0;
	SSPIE = 1;	
}

void  on_interrupt() __interrupt 0{ // обработка прерываний
	if(RCIF == 1){	// поступило прерывание от USART
		if(get9bit() != OK) return;
		switch(cmd){
			case INIT:			init(); break;
			case SET_TIMER:		if(getword()) timer1set();
								else send9bit(ERR_CMD);
								break;
			case TMR_SETTINGS:	sendword(T1H, T1L); break;
			case SPI_send:		if(getword()){
									write_SPI(d_H);
									write_SPI(d_L);}
								break;
			case SPI_send_one:	while(!RCIF); write_SPI(RCREG); break;
			case IMP_RISE:		CKE = 1; break;//данные передаются по заднему фронту
			case IMP_FALL:		CKE = 0; break; //данные передаются по переднему фронту
			case MID_DATA:		SMP = 0; break;
			case END_DATA:		SMP = 1; break;
			case SPI_ON:		// SPI
	// SSPCON: | WCOL | SSPOV | SSPEN | CKP | SSPM3 | SSPM2 | SSPM1 | SSPM0 |
	SSPEN = 1; // (00110010) - выключить SPI, высокий уровень CLK (CKP=1), частота Fosc/64
	// SSPSTAT: | SMP | CKE | - | - | - | - | - | BF |
//	SSPSTAT = 0; // режим работы SPI:  SMP=0 - опрос входа в середине периода
					// CKE=0 - данные передаются по заднему фронту
								SSPIE = 1; break;
			case SPI_OFF:		SSPEN = 0; SSPIE = 0; break;
			case SPI_ACTIVE:	SSPCON = 0x32; TRISC = 0xD0; CKE = 0; SSPIE = 1; break; //TRISC = 0xC0
			case SPI_PASSIVE:	SSPCON = 0x35; TRISC = 0xD8; CKE = 0; SSPIE = 1; break;//TRISC=255;
			case HIG_SPD:		SPBRG = 1; break; // 115200
			case MID_SPD:		SPBRG = 12; break; // 19200
			case TEST:			T1CON = 0; TMR1IF = 0; break;
			case SPI_SHOW:		show_spi(); break;
		}
	}
	if(TMR1IF == 1) // поступило прерывание от таймера
		timer1int(); // обработать прерывание
	if(SSPIF == 1) // прерывание от SPI
		SPI_int(); // обрабатываем
}

void main(){ // основной цикл
	init();
	while(1){};
}

В вашем случае отличие будет лишь в именовании регистров и их количестве (а, еще у 8051 вроде бы отсутствует SPI).

Eddy_Em ☆☆☆☆☆
()

Во, сам нашел пару примеров, но реквест-таки в силе пока =)

Zhbert ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

>Так там ведь тот же С, отличие лишь в регистрах специального назначения.

Тот же С, да. Мне именно поглядеть, как присваивать значения флагов, прописывать их где, инициализировать и т.д.

Zhbert ★★★★★
() автор топика
Ответ на: комментарий от quickquest

На сях, все-таки, попроще программы писать. Тем более что оптимизирует sdcc отлично.

Eddy_Em ☆☆☆☆☆
()

Отрыл лабу из универа - читает память устройства по 1-wire и отсылает через uart.

onewire.{c,h} были взяты из MAXIM Application Note 126 и немного доработаны напильником.

Для keil c51 (или sdcc) и atmel at89s8252.

#include <reg8252.h>
#include <stdio.h>
#include "onewire.h"

void init_uart_t1(void)
{
	/* 8-bit UART, variable baud rate */
	SCON = 0x40;
	/* 8-bit auto-reload timer */
	TMOD = 0x20;
	/* 256 - 22.118 MHz / (384 * 9600 baud) */
	TH1 = TL1 = 0xFA;
	TR1 = 1;
}

/* printf outputs string using putchar function */
char putchar(char c)
{
	SBUF = c;
	while (!TI);
	TI = 0;

	return c;
}

void main(void)
{
	unsigned char i;
	unsigned int device_rom[8];

	init_uart_t1();

	/* Set standard 1-Wire speed */
	OWSetSpeed(1);

	while (1) {
		if (OWTouchReset()) {
			/* No device found */
			continue;
		}

		/* Send "Read ROM" command */
		OWWriteByte(0x33);

		/* Read 8 bytes of data */
		for (i = 0; i < 8; i++) {
			device_rom[i] = OWReadByte();
		}

		if (OWCheckCRC(device_rom)) {
			for (i = 7; i; i--) {
				/* Format to hex and send through UART */
				printf("%02bX", device_rom[i-1]);
			}
		}
	}
}

Вы ведь не напрямую с юсб работаете, а через какой-нибудь мост uart-usb или rs232-usb?

ntp
()
Ответ на: комментарий от ntp

Напрямую, у контроллера есть встроенная конечная точка, ее програмируешь и он работает напрямую с юсб-хабом. Ну всмысле ноги юсб порта напрямую сажаются на ноги контроллера.

Спасибо.

Zhbert ★★★★★
() автор топика

рекомендую книжку «C and the 8051» Thomas W. Schultz

HighwayStar ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.