PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C programm für AT90S4433 in C programm für ATmega8 umwandeln



dremler
08.08.2007, 16:29
hi ich hab mal ne frage an die experten....ich kenn mich selbst mit c kein bisschen aus....

ich habe diesen code:


/* vim: set sw=8 ts=8 si : */
/************************************************** ***********************
Title: linuxfocus frequency counter
Author: guido socher <guido[at]linuxfocus.org>
Copyright: GPL
************************************************** ************************/

#include <io.h>
#include <progmem.h>
#include <interrupt.h>
#include <string-avr.h>
#include <stdlib.h>
#include <sig-avr.h>
#include "lcd.h" /* these are the prototypes and defines for lcd.c */
#include "avr-util.h"
#include "uart.h"

/* output line to scan for button up/down */
#define BUTTONDOWN PD5
#define BUTTONDOWNDDR DDRD
#define BUTTONDOWNPORT PORTD
#define BUTTONUP PD6
#define BUTTONUPDDR DDRD
#define BUTTONUPPORT PORTD

/* Input Push Buttons */
#define SBBUTTON PIND7
#define SBBUTTONDDR DDRD
#define SBBUTTONPIN PIND
#define SBBUTTONPORT PORTD
#define I_BUTTON PINC4
#define I_BUTTONDDR DDRC
#define I_BUTTONPIN PINC
#define I_BUTTONPORT PORTC
#define U_BUTTON PINB3
#define U_BUTTONDDR DDRB
#define U_BUTTONPIN PINB
#define U_BUTTONPORT PORTB
#define UUBUTTON PINB0
#define UUBUTTONDDR DDRB
#define UUBUTTONPIN PINB
#define UUBUTTONPORT PORTB

/* current limit input and led */
#define ILIMIT PIND3
#define ILIMITDDR DDRD
#define ILIMITPIN PIND
#define ILED PC5
#define ILEDDDR DDRC
#define ILEDPORT PORTC
/* PWMOUT0= current control, software pwm */
#define PWMOUT0 PB2
#define PWMOUT0DDR DDRB
#define PWMOUT0PORT PORTB
/* PWMOUT1= voltage control, internal hardware pwm */
#define PWMOUT1 PB1
#define PWMOUT1DDR DDRB
#define PWMOUT1PORT PORTB
static char uart_outbuf[UART_RX_BUFFER_SIZE+1];

/* max 2.2A output, can be up to 3A (3000),
* change, depends on the transformer you have */
#define MAX_I 2200
/* minial stepping for I, set to 50 for MAX_I=3000
* otherwise set to 25, change this dependent on hardware */
#define IMINSTEP 25
static unsigned char ipwm_h; /* time that PWM for I is high */
static unsigned char ipwm_phase; /* flag indicating whether we are now producing a 1 or a zero */
static int ival; /* 16 bit, the current in mA */

/* max 16V output, change dependent on the transformer you have */
#define MAX_U 160
static int uval; /* 16 bit, the Voltage in 0.1 V units, eg. 50=5V */
static unsigned char mode; /* 0=normal operation, 1=I-limit, 2=standby */
static unsigned char oldmode; /* 0=normal operation, 1=I-limit, 2=standby */
static unsigned char tmpval[3]; /* 24 bit, needed for exact math in set_u */
static unsigned char tmpval2[3]; /* 24 bit, needed for exact math in set_u */

#define reply_ok() uart_sendstr_P("ok\n")
#define reply_err() uart_sendstr_P("err\n")

/* there is only support for 16bit math operations in libc.
* to get more accurate math we have to write our own functions */

/* *x is 24 bit, result is in x (x=in/out value), y *256+256 must be < 32768*/
unsigned char divXbyY(unsigned char *x,unsigned char y){
unsigned char loop,rest;
unsigned int tmp; // 16 bit
loop=3;
/* start with highest byte */
rest=0;
while(loop>0){
tmp=rest * 256 + x[loop-1];
x[loop-1]=tmp / y;
rest=tmp % y;
loop--;
}
return(rest);
}

/* *x is 24 bit, result is in x (x=in/out value), the bigger
* number must go into x, 8bit of x times y must never go over 32768 */
void multiXbyY(unsigned char *x,int y){
unsigned char loop;
unsigned int tmp,over; // 16 bit
loop=0;
over=0;
while(loop<3){
tmp= x[loop] * y + over;
over=tmp/256;
x[loop]=tmp - (over*256);
loop++;
}
}


/* convert a 2 time 8 bit interger (16 bit=i[0] and i[1], i[2] is set to zero,
* i is 24bit but only 16 bit are used) to decimal ascii and
* print it using the printfun. Padd all the digits to 4 (but we can handle full
* 16 bit if needed)
* If addcomma is set then the number will be printed by 1/10. That is
* 35 will be " 3.5" and 3 will be " 0.3" */
/* note: this function modifies *i !! */
void longtoascii(void (*printfun)(char),unsigned char *i,unsigned char addcomma)
{
char str[7];
unsigned char pos=7;
unsigned char j=0;
i[2]=0;
do{
str[pos-1]=divXbyY(i,10);
str[pos-1]+= '0';
pos--;
j++;
/* write a "," after the last digit from the right */
if (j==1 && addcomma==1){
str[pos-1]=',';
pos--;
}
}while((i[0]|i[1]) && pos > 0);
if (str[pos] == ',' && pos > 0){
/* add the missing zero for 3 -> 0.3 */
str[pos-1]='0';
pos--;
}
/* add spaces to padd up to 4 digits */
j=pos-3;
while(j>0){
(*printfun)(' ');
j--;
}
/* now reverse the string and print */
while(pos<7){
(*printfun)(str[pos]);
pos++;
}
}



/* this function will be called in if the 8bit timer goes from ff to 00 */
SIGNAL(SIG_OVERFLOW0)
{
/* stop 8bit timer */
outp(0,TCCR0);
if (ipwm_phase==1 && ipwm_h !=0){
/* now we will produce a "1" at the output */
/* time that we should remain "1" is ipwm_h */
outp(0xFF-ipwm_h,TCNT0); /* set start value */
sbi(PWMOUT0PORT,PWMOUT0); /* 1 */
ipwm_phase=0;
}else{
/* now we will produce a "0" at the output */
/* time that we should remain "1" is ipwm_h */
outp(ipwm_h,TCNT0); /* set start value */
cbi(PWMOUT0PORT,PWMOUT0); /* 0 */
ipwm_phase=1;
}
/* start 8bit timer with 62500Hz, clock/64 */
outp(3,TCCR0);
}

/* set current limit in a non linear way, 0=up, 1=down */
unsigned char step_i(unsigned char direction)
{
if (ival<200){
/* step in 50mA (or 25) units and round to the next 50 (or 25)*/
ival=ival/IMINSTEP; /* round off values set via rs232 */
ival=ival*IMINSTEP;
if (direction){
ival-=IMINSTEP;
}else{
ival+=IMINSTEP;
}
return(0);
}
if (ival<1000){
/* step in 100mA units and round to the next 100 */
ival=ival/100; /* round off values set via rs232 */
ival=ival*100;
if (direction){
ival-=100;
}else{
ival+=100;
}
return(0);
}
/* more than 1A */
/* step in 200mA units and round to the next 200 */
ival=ival/200; /* round off values set via rs232 */
ival=ival*200;
if (direction){
ival-=200;
}else{
ival+=200;
}
return(0);
}

/* set the current limit , reads ival and writes ipwm_h */
void set_i(void)
{
int a;
if (ival>MAX_I){
ival=MAX_I;
}
if (ival<50){ /* at least 50 mA, with 8bit this is the lower limit */
ival=50;
}
if (ival<140){
/* change this to calibrate */
/* y=(a/1000) *x */
//a=65; /* use this if R38=33K */
a=94; /* use this if R38=120K */
}else if (ival<500){
/* change this to calibrate */
/* y=(a/1000) *x */
//a=75; /* use this if R38=33K */
a=107; /* use this if R38=120K */
}else{
/* change this to calibrate */
/* y=(a/1000) *x */
//a=82; /* use this if R38=33K */
a=111; /* use this if R38=120K */
}
tmpval[0]=ival & 0xff;
tmpval[1]=(ival >> 8);
tmpval[2]=0;
multiXbyY(tmpval,a);
divXbyY(tmpval,100);
divXbyY(tmpval,10);
ipwm_h=tmpval[0];
/* debug, activate to calibarate */
//longtoascii(uart_sendchar,tmpval,0);
//uart_sendchar(' ');
}

/* set the voltage , reads uval and writes OCR1 */
void set_u(void)
{
int a;
unsigned char c,b;
if (uval>MAX_U){
uval=MAX_U;
}
if (uval<0){
uval=0;
}
/* below 1V the accuracy is limited because the values are
* too much quantisized (the digital resolution gets smaller)
* If you draw a curve you find that it is 99% linear */

/* remove the programming cable if you calibrate. It influences
* the output values slightly */
if (uval<5){
/* change this to calibrate */
a=250; /* y=(a/(b*c)*x */
b=10;
c=10;
}else if (uval<25){
/* change this to calibrate */
a=305; /* y=(a/(b*c)*x */
b=10;
c=10;
/*--- end calibrate ---*/
}else if (uval<120){
/* change this to calibrate */
a=793; /* y=(a/(b*c)*x */
b=10;
c=25;
/*--- end calibrate ---*/
}else{
/* change this to calibrate */
a=637; /* y=(a/(b*c)*x */
b=20;
c=10;
/*--- end calibrate ---*/
}
/* 24bit math for better accuraty */
tmpval[0]=a & 0xff;
tmpval[1]=(a >> 8) & 0xff;
tmpval[2]=0;
multiXbyY(tmpval,uval); /* uval is smaller than tmpval */
divXbyY(tmpval,b);
divXbyY(tmpval,c);
if (mode!=2){ /* do not mess up standby state */
outp( tmpval[1],OCR1H); /* set pwm high time*/
outp( tmpval[0],OCR1L); /* set pwm high time*/
}
/* debug, activate to calibarate */
//longtoascii(uart_sendchar,tmpval,0);
//uart_sendchar(' ');
}

void toggle_standby(void){
if (mode == 2){
/* set U to zero in standby but do not modify
* the displayed value */
outp( 0,OCR1H); /* set pwm high time*/
outp( 0,OCR1L); /* set pwm high time*/
ipwm_h=0; /* current = 0 */
}
if (mode ==0){
/* activate voltage output again */
sbi(ILEDPORT,ILED); /* red led off */
set_i();
set_u();
}
}

/* update rs232*/
void updaters232(void)
{
uart_sendstr_P("u:");
tmpval[0]=uval & 0xff;
tmpval[1]=(uval >> 8);
longtoascii(uart_sendchar,tmpval,0);
if (mode==2){
uart_sendstr_P(" s:1 i:");
}else{
uart_sendstr_P(" s:0 i:");
}
tmpval[0]=ival & 0xff;
tmpval[1]=(ival >> 8);
longtoascii(uart_sendchar,tmpval,0);
if (mode==1){
uart_sendstr_P(" l:1\n");
}else{
uart_sendstr_P(" l:0\n");
}
}

/* update display */
void updatedisplay(void)
{
lcd_clrscr();
lcd_puts_P("u: ");
tmpval[0]=uval & 0xff;
tmpval[1]=(uval >> 8);
longtoascii(lcd_putc,tmpval,1);
lcd_puts_P(" V ");
if (mode==0){
lcd_puts_P("<-");
}
if (mode==2){
lcd_puts_P("standby");
}
lcd_gotoxy(0,1);
lcd_puts_P("i: ");
tmpval[0]=ival & 0xff;
tmpval[1]=(ival >> 8);
longtoascii(lcd_putc,tmpval,0);
lcd_puts_P(" mA ");
if (mode==1){
lcd_puts_P("<-");
}
}


int main(void)
{
unsigned char i,rxresult,status,j,ilimitdebounce;
unsigned int ignorebutton;
unsigned int blink; /* blink in standby mode */
char cmd;
char *val;


/* initialize display, cursor off */
lcd_init(LCD_DISP_ON);
/* current limit detection as input line */
cbi(ILIMITDDR,ILIMIT);
/* red current limit LED as output */
sbi(ILEDDDR,ILED);
sbi(ILEDPORT,ILED);
/* initialize rs232 */
uart_init();

/* initialize PWM output 0 (current control) as output */
sbi(PWMOUT0DDR,PWMOUT0);
/* setup the 8bit timer for current control */
sbi(TIMSK,TOIE0); /* enable T0 overflow0 interrupt */
outp(0,TCNT0); /* start value */
/* start 8bit timer with 62500Hz, clock/64 overflow0 every 64 */
outp(3,TCCR0);
ipwm_phase=0; /* initialize */
ival=100; /* initialize default current */

/* initialize PWM output 1 (voltage control) as output */
sbi(PWMOUT1DDR,PWMOUT1);
/* setup the 16bit timer for voltage control, in the
* 4433 this timer supports hardware pwm therefore we
* do not have to implement it in software */
outp(0x83,TCCR1A); /* enable 10bit pwm and clear on compare match */
outp(0x2,TCCR1B); /* run at 1/8 of crystal freq */
/* write high byte first */
outp(0x0,TCNT1H); /* set counter to zero*/
outp(0x0,TCNT1L); /* set counter to zero*/
uval=50; /* initialize default voltage, 50=5.0V */

mode=0;
oldmode=mode;

ignorebutton=0;
ilimitdebounce=0;
blink=0;

/* button as digital input */
cbi(I_BUTTONDDR,I_BUTTON);
cbi(U_BUTTONDDR,U_BUTTON);
cbi(UUBUTTONDDR,UUBUTTON);
cbi(SBBUTTONDDR,SBBUTTON);
/* pull up resistor on */
sbi(I_BUTTONPORT,I_BUTTON);
sbi(U_BUTTONPORT,U_BUTTON);
sbi(UUBUTTONPORT,UUBUTTON);
sbi(SBBUTTONPORT,SBBUTTON);
/* the buttons are multiplexed, enable output lines */
sbi(BUTTONDOWNDDR,BUTTONDOWN);
sbi(BUTTONUPDDR,BUTTONUP);


sei(); /* enable interrupt */

/* now we can use uart/lcd display */
set_i();
set_u();
updatedisplay();

while(1){
/* first check up (++) buttons */
sbi(BUTTONDOWNPORT,BUTTONDOWN);
cbi(BUTTONUPPORT,BUTTONUP);
j=0;
/* ignorebutton is needed for debounce */
while(j<2 && ignorebutton==0){
if (bit_is_clear(I_BUTTONPIN,I_BUTTON)){
step_i(j);
set_i();
updatedisplay();
updaters232();
ignorebutton=15000;
}
if (bit_is_clear(U_BUTTONPIN,U_BUTTON)){
if (j==0){
uval+=1;
}else{
uval-=1;
}
set_u();
updatedisplay();
updaters232();
ignorebutton=15000;
}
if (bit_is_clear(UUBUTTONPIN,UUBUTTON)){
if (j==0){
uval+=10;
}else{
uval-=10;
}
set_u();
updatedisplay();
updaters232();
ignorebutton=15000;
}
if (bit_is_clear(SBBUTTONPIN,SBBUTTON)){
if (mode != 2){
mode=2;
}else{
mode=0; /* if i-limit is active then this will change below */
}
toggle_standby();
ignorebutton=20000;
}
/* now check down (--) buttons */
cbi(BUTTONDOWNPORT,BUTTONDOWN);
sbi(BUTTONUPPORT,BUTTONUP);
j++;
}

if (ignorebutton) ignorebutton--;
if (ilimitdebounce) ilimitdebounce--;
if (mode!=2){ /* not standby */
if (bit_is_clear(ILIMITPIN,ILIMIT)){
mode=1;
ilimitdebounce=200;
/* red led on */
cbi(ILEDPORT,ILED);
}else{
if(mode==1 && ilimitdebounce==0){
mode=0;
/* red led off */
sbi(ILEDPORT,ILED);
}
}
}

if (mode!=oldmode){
updatedisplay();
updaters232();
}
oldmode=mode;

/* flash red led in standby */
if (mode==2){
if (blink > 15000){
blink=0;
}
if (blink <2000){
cbi(ILEDPORT,ILED); /* red led on */
}else{
sbi(ILEDPORT,ILED); /* red led off */
}
blink++;
}

rxresult=uart_getrxbufnl(uart_outbuf);
if (rxresult==0){
continue;
}
/* valid command are:
* i=0-3000 u=0-300 s=0-1 s=? u=? i=? */
/* now parse the comands and act on them */
if (strlen(uart_outbuf) < 3) {
reply_err();
continue;
}
if (uart_outbuf[1] != '='){
reply_err();
continue;
}
val=&(uart_outbuf[2]);
cmd=uart_outbuf[0];
status=0;
/* act on the commands */
if (cmd=='i'){
if (*val== '?'){
updaters232();
continue;
}
ival=(int)atoi(val);
set_i();
updatedisplay();
status=1;
}
/* act on the commands */
if (cmd=='u'){
if (*val== '?'){
updaters232();
continue;
}
uval=(int)atoi(val);
set_u();
updatedisplay();
status=1;
}
if (cmd=='s'){
i=*val;
if (i == '?'){
updaters232();
continue;
}
if (i == '1'){
mode=2;
status=1;
}
if (i == '0'){
mode=0; /* if i-limit is active then this will change in the next loop */
status=1;
}
toggle_standby();
}
/* command handling done. now return status */
if (status==1){
reply_ok();
}else{
reply_err();
}
}

}



das ganze steuert ein labornetzteil....laut der datenblätter ist die pinbelegung gleich.... (es sind nur einige zusatzfunktionen dazugekommen..vgl:http://www1.jaycar.com.au/images_uploaded/ZZ8730.pdf und http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf )

wie und was muss ich nun an dem c programm anpassen? ich weiß nur das man ja zb in bascom eine regfile angeben muss damit das programm die speicherverteilung und die adressen weiß.....muss ich das auch in c????

dankeschön...

ach wens interessiert....diese lab netzteil hier:http://www.linuxfocus.org/Deutsch/November2002/article251.shtml

izaseba
08.08.2007, 17:06
tja, es hat sich einiges getan seit 2002...
Es reicht nicht aus im Makefile den µC auf m8 zu setzen,
die Bibliotheknamen sind anders, SIGNAL sollte nicht mehr verwendet werden, wobei das noch nicht das Problem ist, dann gibt es sowas wie


outp(0xFF-ipwm_h,TCNT0); /* set start value */
sbi(PWMOUT0PORT,PWMOUT0); /* 1 */
k.A. ob der Guido da irgendwo ein #define darauf gesetzt hat, oder waren diese funktionen/makros in avr-gcc von 2002 drin.

Fazit:
Wenn man sich mit C auskennt, ein Abend Arbeit, wenn man kein Plan davon hat, unlösbar.

Gruß Sebastian

linux_80
08.08.2007, 17:29
Hallo,

beim M8 heisst es im DB, das AGND und AVCC auch verkabelt sein sollen, auch wenn man die Ports nur digital verwendet, im Schaltplan ist das aber nicht so !
Dürfte aber nicht so schwierig sein das einzubauen.

Ansonsten hat izaseba schon das wichtigste gesagt.

dremler
08.08.2007, 20:53
ok:( ich kenn mich damit leider garnicht aus (mit c...) und den AT90S4433 wird net mehr produziert....ich werd gleich mal ne anfrage starten ob jmd noch ein oder 2 daheim rumliegen hat und sie mir überlässt?! ansonsten muss ich drauf hoffen das jmd so nett ist un sich nen abend hinsetzt...;)

izaseba
08.08.2007, 21:20
Ja, es dürfte wohl die einfachste Lösung sein an so ein paar alte 4433 dranzukommen ( Vielleicht den Guido selber fragen ;-) )
Aber denke daran, daß Du fertige *.hex Dateien haben mußt, sonst bekommst Du das Programm nicht übersetzt(es sei denn, du kommst an die avr-gcc Version von 2002)
Wenn Du sonst keine Hilfe bekommst kannst Du mir mal eine PN schreiben vielleicht kann ich Dir dann helfen...

Gruß Sebastian

dremler
08.08.2007, 21:50
ich habe ihm mal ne mail geschrieben...mal schaun ob er antwortet...

edit:

http://sourceforge.net/project/showfiles.php?group_id=68108&package_id=66543 hier die versionen ganz unten dürften doch gehen oder?

izaseba
08.08.2007, 22:29
hier die versionen ganz unten dürften doch gehen oder?
Auf den ersten Blick ja, kannst ja probieren ;-)

dremler
10.08.2007, 23:28
hi ich wollt euch der vollständigkeithalber mal auf dem laufenden halten.....der entwickler der schaltung hat mir kurz und knapp diesen link zugesandt...

http://shop.tuxgraphics.org/electronic/microcontroller.html#a379

jaja jeder will sein geld machen...aber ich hab die tile ja schon....
aber ich bin glücklicherweise auf einen netten menschen (aus einem anderen forum ) gestoßen der mir 2 AT90S4433 zur verfügung stellen kann (einer als reserve...)

dremler
14.08.2007, 20:22
so ich habe jmd gefunden der mir welche geschickt hat....ich kann also die fertig hex übertragen....