Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Write/Read to EEPROM... question.

Status
Not open for further replies.

RobertD

New Member
Hi folks, I've been trying to get a value to write and read into EEPROM, but the ADDRess of the write register doesn't get read as an address, but as the value in it, and the NEW value I'm trying to put in doesn't go in. Same thing when I read, the ADDRess reads the content instead of the location.

I tried to move some of the commands around a bit to see if that was the problem, but nothing works so far.

Code:
LIST	p=16F88
	include "P16F88.inc"
	__config _CONFIG1, _WDT_OFF & _INTRC_IO & _MCLR_ON & _LVP_OFF
	ERRORLEVEL 0, -302



	ADDR	equ	0x110

	cblock	 0x20
	 OLD, NEW,
	endc


;WRITE TO EEPROM__________________________


	org 0x00


		movlw		h'ab'
		movwf		NEW
		movlw		h'02'
		movwf		OLD

		
		banksel		TRISA 		;bank 1
		movlw		0x72		;8MHz clock
		movwf		OSCCON


		
		banksel		EEADR 	             ;Bank 2
		movf 		ADDR,W 		;Address to write to
		movwf 		EEADR 		
		movf 		NEW, W 		;Data to write
		movwf 		EEDATA 				
	
		banksel		EECON1		 ;Bank 3
		bcf 		EECON1, EEPGD 	;Point to Data memory
		bsf 		EECON1, WREN 	;Enable writes
		movlw 		0x55 		;Write 55h to
		movwf 		EECON2 		;EECON2
		movlw 		0xAA 		;Write AAh to
		movwf 		EECON2 		;EECON2
		bsf 		EECON1, WR 	;Start write operation
		btfsc 		EECON1, WR 	;Wait for write to finish
		goto 		$-1 				
		bcf 		EECON1, WREN 	;Disable writes
;_____________________________________________________________________________________

;READ EEPROM 

		banksel		EEADR
		movf 		ADDR, W 	;address to read from
		movwf 		EEADR 			
		banksel		EECON1		;Bank 3
		bcf 		EECON1, EEPGD	;Point to Data memory
		bsf 		EECON1, RD 	;Start read operation
		banksel		EEADR 		;Bank 2
		movf 		EEDATA, W 	; W=DATA from EEPROM
		movwf		OLD				
	


	end
 
Last edited:
Hi,
The location of the general purpose register is in bank 2, 0x110. But what's the value in it? From your code, the content in ADDR is the address location of the EEPROM. So the value in ADDR should be predefined.
 
I put ADDR 0x110, which is in bank 2 according to the memory map of the 16F88. It has no value in it, I'm trying to put one in. I'm trying to put NEW value in EEPROM at 0x110, which I named ADDR.
 
Hi,
I think you have confused with the RAM and the EEPROM. You're correct that the general purpose register 0x110 is in bank2, but you're wrong that it has no value in it. Every time power on, the value in the RAM is unspecified. So you need to predefine it. Also you won't get EEPROM at 0x110, because the EEPROM is 256 wide so the address location of the EEPROM is from 0x00 to 0xff.

The address of the EEPROM doesn't need to be in bank2 or any other bank, because it is EEPROM, which is another type of memory but not the RAM. Just put the address (from 0x00 to 0xff whichever you like) into EEADR, then put the data into EEDATA and done. For reading it back, do the same. Put the address into EEADR, then read from EEDATA.
 
You absolutely must have correct banking. I use the common "shared" locations 70..7F for my EEPROM routine variables so that I can access them no matter what bank I happen to be in. Code below is for 16F88...

Mike


Code:
;
;  read crystal calibration TRIM values from EEPROM
;
        clrf    EEPTR           ; EEPROM address 00               |B0
        call    Rd_EEProm       ;                                 |B0
        movwf   CCNT            ; setup correction count          |B0
        incf    EEPTR,f         ; EEPROM address 01               |B0
        call    Rd_EEProm       ;                                 |B0
        movwf   CVAL            ; setup correction value, FF/01   |B0
Code:
EEPTR   equ     h'74'   ; EEPROM address pointer
EEVAL   equ     h'75'   ; EEPROM data

;******************************************************************
;
;  entry: W contains data,  EEPTR contains address, 0..255
;
Wr_EEProm
        movwf   EEVAL           ; save data                       |B0
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              |B2
        movf    EEPTR,W         ; get address                     |B2
        movwf   EEADR           ; set address                     |B2
        movf    EEVAL,W         ; get data                        |B2
        movwf   EEDATA          ; set data                        |B2
        bsf     STATUS,RP0      ; bank 3                          |B3
        bcf     EECON1,EEPGD    ; select data memory              |B3
        bsf     EECON1,WREN     ; enable writes                   |B3
        bcf     INTCON,GIE      ; disable interrupts              |B3
        movlw   h'55'           ;                                 |B3
        movwf   EECON2          ;                                 |B3
        movlw   h'AA'           ;                                 |B3
        movwf   EECON2          ;                                 |B3
        bsf     EECON1,WR       ; initiate the write              |B3
Wr_chk
        btfsc   EECON1,WR       ; last write complete?            |B3
        goto    Wr_chk          ; no, branch                      |B3
        bsf     INTCON,GIE      ; enable interrupts               |B3
        bcf     EECON1,WREN     ; disable writes                  |B3
        bcf     STATUS,RP0      ; bank 2                          |B2
        bcf     STATUS,RP1      ; bank 0                          |B0
        return                  ;                                 |B0
;******************************************************************
;
;
;
Rd_EEProm
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              |B2
        movf    EEPTR,W         ; get address                     |B2
        movwf   EEADR           ; set address                     |B2
        bsf     STATUS,RP0      ; bank 3                          |B3
        bcf     EECON1,EEPGD    ; select data memory              |B3
        bsf     EECON1,RD       ; perform RD operation            |B3
        bcf     STATUS,RP0      ; bank 2                          |B2
        movf    EEDATA,W        ; get data byte                   |B2
        bcf     STATUS,RP1      ; bank 0                          |B0
        return                  ;                                 |B0
 
Last edited:
Alright thanks guys, I'll play with these tomorrow, after work. And see if I can get it to work. I didn't really know that the EEPROM was not on the map, but I figured that might be where I was wrong. I suppose the internal eeprom is like an external eeprom, and must be treated in a similar way. And you're right it does read FF for value, but I thought that was random, and certainly not what I needed. But I see the error now.

And Mike thanks for the proper nesting for the call. I'll definitely use that in my final setup.
 
Last edited:
Hi Mike.

I'm using your set up to write a value (AB) into EEPROM, and to read it back and retrieve it via OLD registry. But it's returning FF, and not AB, which is what I wrote. ( I removed the interrupt commands enable/disable since I don't need them.)

Code:
LIST	p=16F88
	include "P16F88.inc"
	__config _CONFIG1, _WDT_OFF & _INTRC_IO & _MCLR_ON & _LVP_OFF
	ERRORLEVEL 0, -302

		goto start

EEPTR   equ     h'74'   ; EEPROM address pointer
EEVAL   equ     h'75'   ; EEPROM data
OLD      equ     h'76'
;******************************************************************
;

;  entry: W contains data,  EEPTR contains address, 0..255
;
Wr_EEProm
        movwf   EEVAL           ; save data                       |B0
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              |B2
        movf    EEPTR,W         ; get address                     |B2
        movwf   EEADR           ; set address                     |B2
        movf    EEVAL,W         ; get data                        |B2
        movwf   EEDATA          ; set data                        |B2
        bsf     STATUS,RP0      ; bank 3                          |B3
        bcf     EECON1,EEPGD    ; select data memory              |B3
        bsf     EECON1,WREN     ; enable writes                   |B3
  
        movlw   h'55'           ;                                 |B3
        movwf   EECON2          ;                                 |B3
        movlw   h'AA'           ;                                 |B3
        movwf   EECON2          ;                                 |B3
        bsf     EECON1,WR       ; initiate the write              |B3
Wr_chk
        btfsc   EECON1,WR       ; last write complete?            |B3
        goto    Wr_chk          ; no, branch                      |B3
       
        bcf     EECON1,WREN     ; disable writes                  |B3
        bcf     STATUS,RP0      ; bank 2                          |B2
        bcf     STATUS,RP1      ; bank 0                          |B0

        return                  ;                                 |B0
;******************************************************************
;
;
;
Rd_EEProm
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              |B2
        movf    EEPTR,W         ; get address                     |B2
        movwf   EEADR           ; set address                     |B2
        bsf     STATUS,RP0      ; bank 3                          |B3
        bcf     EECON1,EEPGD    ; select data memory              |B3
        bsf     EECON1,RD       ; perform RD operation            |B3
        bcf     STATUS,RP0      ; bank 2                          |B2
        movf    EEDATA,W        ; get data byte                   |B2
        bcf     STATUS,RP1      ; bank 0                          |B0
        return                  ;     



	start

		banksel		TRISA 		;bank 1
		movlw		0x72		;8MHz clock
		movwf		OSCCON

 
		movlw		0xAB
		call 		Wr_EEProm
		nop
		call 		Rd_EEProm
		movwf		OLD

		end
 
Last edited:
I changed the code a bit and added the address as data into the EEPTR register. Everything works fine up to getting the address from EEPTR into EEADR I get nothing there. I entered the address of EEPTR 0x74 as data into the register EEPTR, and want to move that into EEADR, but I read 0xFF in the EEADR register. Obviously the address doesn't get loaded.


Code:
LIST	p=16F88
	include "P16F88.inc"
	__config _CONFIG1, _WDT_OFF & _INTRC_IO & _MCLR_ON & _LVP_OFF
	ERRORLEVEL 0, -302

		goto start

EEPTR   equ     h'74'   ; EEPROM address pointer
EEVAL   equ     h'75'   ; EEPROM data
OLD 	equ		h'76'
;******************************************************************
;

;  entry: W contains data,  EEPTR contains address, 0..255
;
Wr_EEProm
        movwf   EEVAL           ; save data                       
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)             
        movf    EEPTR,W           ; get address                     
        movwf   EEADR           ; setaddress                                      

      movf    EEVAL,W         ; get data                        
        movwf   EEADR           ; set data                        
        bsf     STATUS,RP0      ; bank 3                          
        bcf     EECON1,EEPGD    ; select data memory              
        bsf     EECON1,WREN     ; enable writes                   
  
        movlw   h'55'           ;                                 
        movwf   EECON2          ;                                 
        movlw   h'AA'           ;                                 
        movwf   EECON2          ;                                 
        bsf     EECON1,WR       ; initiate the write              
Wr_chk
        btfsc   EECON1,WR       ; last write complete?            
        goto    Wr_chk          ; no, branch                      
       
        bcf     EECON1,WREN     ; disable writes                  
        bcf     STATUS,RP0      ; bank 2                          
        bcf     STATUS,RP1      ; bank 0                          

        return                  ;                                 
;******************************************************************
;
;
;
Rd_EEProm
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              
        movf    EEPTR,W         ; get address                     
        movwf   EEADR   ; set address                     
        bsf     STATUS,RP0      ; bank 3                          
        bcf     EECON1,EEPGD    ; select data memory              
        bsf     EECON1,RD       ; perform RD operation            
        bcf     STATUS,RP0      ; bank 2                          
        movf    EEDATA,W        ; get data byte                   
        bcf     STATUS,RP1      ; bank 0                          
        return                  ;     



	start

		banksel		TRISA 		;bank 1
		movlw		0x72		;8MHz clock
		movwf		OSCCON
		
 		movlw		h'74
		movwf		EEPTR
		movlw		0xAB
		call 		Wr_EEProm
		nop
		call 		Rd_EEProm
		movwf		OLD
		nop
		end
 
I just tried it on a real 16F88 circuit and it works fine. I wrote characters 'a' through 'h' into EEPROM starting at address 00 and then read those same eight locations back from EEPROM and printed them through the serial port as hexidecimal values...

Mike

curious-png.21022


Code:
        list p=16F88, b=8, c= 102, n=71, t=on, st=off, f=inhx32
;******************************************************************
;*                                                                *
;*  Filename: 16F88 EEPROM Test.asm                               *
;*    Author: Mike McLaren, K8LH                                  *
;*      Date: 15-Jul-08                                           *
;*                                                                *
;*   16F88 EEPROM Test Program                                    *
;*                                                                *
;*                                                                *
;*     MPLab: 8.01    (tabs=8)                                    *
;*                                                                *
;******************************************************************

        processor PIC16F88
        include   P16F88.INC
        errorlevel -302

        __CONFIG  _CONFIG1, _LVP_OFF&_BODEN_OFF&_PWRTE_ON&_WDT_OFF&_HS_OSC
        __CONFIG  _CONFIG2, _IESO_OFF&_FCMEN_OFF
;
;       _CP_OFF                 ; default
;       _CCP1_RB0               ; default
;       _DEBUG_OFF              ; default
;       _WRT_PROTECT_OFF
;       _CPD_OFF                ; default
;       _LVP_OFF
;       _BODEN_OFF
;       _MCLR_ON                ; default
;       _PWRTE_ON
;       _WDT_OFF
;       _INTRC_IO or _HS_OSC
;

PTRL    equ     h'20'           ; PutString routine
PTRH    equ     h'21'           ; PutString routine
TEMP    equ     h'22'           ; PutByte routine
counter equ     h'27'           ;
;
EEPTR   equ     h'70'           ;
EEVAL   equ     h'71'           ;

;
;  eeprom test value
;
;       org     h'2100'         ; test, ignore
;       de      h'FF',h'FF',h'FF',h'FF'

;******************************************************************
;*                                                                *
;*                                                                *
;*                                                                *
;******************************************************************
Start   equ     h'0100'         ; bootloader present

        org     h'0000'+Start   ; 0000 or 0100 (bootloader)

Reset_Vector
        clrf    STATUS          ; force bank 0, IRP 0             |B0
        clrf    PORTA           ; clear PORT A latches            |B0
        clrf    PORTB           ; clear PORT B latches            |B0
        bsf     STATUS,RP0      ; bank 1                          |B1
        clrf    ANSEL           ; setup PORT A digital I/O        |B1
        clrf    TRISA           ; setup PORT A all outputs        |B1

        movlw   d'64'           ; 25 (8-MHz) or 64 (20-MHz)       |B1
        movwf   SPBRG           ; 19200 baud                      |B1
        movlw   b'00100100'     ;                                 |B1
        movwf   TRISB           ; set RB5/TX & RB2/RX as inputs   |B1
        movlw   b'00100100'     ; TXEN=1, SYNC=0, BRGH=1, TX9=0   |B1
        movwf   TXSTA           ; Async, 8, 1, none               |B1
        bcf     STATUS,RP0      ; select Bank 0                   |B0
        movlw   b'10010000'     ; SPEN=1, TX9=0, CREN=1, ADDEN=0  |B0
        movwf   RCSTA           ; enable serial port              |B0
        movf    RCREG,W         ; flush Rx Buffer                 |B0
        movf    RCREG,W         ;                                 |B0

        call    Greeting        ; print greeting string           |B0

        clrf    EEPTR           ; EE address 00                   |B0
        movlw   'a'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 01                   |B0
        movlw   'b'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 02                   |B0
        movlw   'c'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 03                   |B0
        movlw   'd'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 04                   |B0
        movlw   'e'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 05                   |B0
        movlw   'f'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 06                   |B0
        movlw   'g'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0
        incf    EEPTR,F         ; EE address 07                   |B0
        movlw   'h'             ;                                 |B0
        call    Wr_EEProm       ;                                 |B0

test    movlw   8               ;                                 |B0
        movwf   counter         ;                                 |B0
        movlw   0               ;                                 |B0
        call    PutHex          ;                                 |B0
        movlw   ':'             ;                                 |B0
        call    Put232          ;                                 |B0
        movlw   ' '             ;                                 |B0
        call    Put232          ;                                 |B0
        clrf    EEPTR           ; EE address 00                   |B0
t1      call    Rd_EEProm       ;                                 |B0
        call    PutHex          ;                                 |B0
        movlw   ' '             ;                                 |B0
        call    Put232          ;                                 |B0
        incf    EEPTR,F         ;                                 |B0
        decfsz  counter,F       ;                                 |B0
        goto    t1              ;                                 |B0
;
Loop    call    Get232          ;                                 |B0
        call    Put232          ;                                 |B0
        goto    Loop            ;                                 |B0

;******************************************************************
;
Get232  btfss   PIR1,RCIF       ; character available?            |B0
        goto    Get232          ; no, branch, else                |B0
        movf    RCREG,W         ; get character                   |B0
        return                  ;                                 |B0
;
Put232  btfss   PIR1,TXIF       ; transmit buffer empty?          |B0
        goto    Put232          ; no, branch, else                |B0
        movwf   TXREG           ; send character                  |B0
        return                  ;                                 |B0
;
PutHex  movwf   TEMP            ; save byte                       |B0
        swapf   TEMP,W          ; swap nibbles in W               |B0
        call    Hex2Asc         ; process left nibble             |B0
        movf    TEMP,W          ; process right nibble            |B0
Hex2Asc andlw   b'00001111'     ; mask off left nibble            |B0
        addlw   h'36'           ;                                 |B0
        btfsc   STATUS,DC       ;                                 |B0
        addlw   h'07'           ;                                 |B0
        addlw   0-6             ; ($FA)                           |B0
        goto    Put232          ; print ASCII nibble              |B0
;
Wr_EEProm
        movwf   EEVAL           ; save data                       |B0
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              |B2
        movf    EEPTR,W         ; get address                     |B2
        movwf   EEADR           ; set address                     |B2
        movf    EEVAL,W         ; get data                        |B2
        movwf   EEDATA          ; set data                        |B2
        bsf     STATUS,RP0      ; bank 3                          |B3
        bcf     EECON1,EEPGD    ; select data memory              |B3
        bsf     EECON1,WREN     ; enable writes                   |B3
;       bcf     INTCON,GIE      ; disable interrupts              |B3
        movlw   h'55'           ;                                 |B3
        movwf   EECON2          ;                                 |B3
        movlw   h'AA'           ;                                 |B3
        movwf   EECON2          ;                                 |B3
        bsf     EECON1,WR       ; initiate the write              |B3
Wr_chk
        btfsc   EECON1,WR       ; last write complete?            |B3
        goto    Wr_chk          ; no, branch                      |B3
;       bsf     INTCON,GIE      ; enable interrupts               |B3
        bcf     EECON1,WREN     ; disable writes                  |B3
        bcf     STATUS,RP0      ; bank 2                          |B2
        bcf     STATUS,RP1      ; bank 0                          |B0
        return                  ;                                 |B0
;
Rd_EEProm
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              |B2
        movf    EEPTR,W         ; get address                     |B2
        movwf   EEADR           ; set address                     |B2
        bsf     STATUS,RP0      ; bank 3                          |B3
        bcf     EECON1,EEPGD    ; select data memory              |B3
        bsf     EECON1,RD       ; perform RD operation            |B3
        bcf     STATUS,RP0      ; bank 2                          |B2
        movf    EEDATA,W        ; get data byte                   |B2
        bcf     STATUS,RP1      ; bank 0                          |B0
        return                  ;                                 |B0

Greeting
        movlw   high sHello     ;                                 |B0
        movwf   PTRH            ;                                 |B0
        movlw   low sHello      ;                                 |B0
        movwf   PTRL            ;                                 |B0
;
PutString
        call    GetTable        ; get a table character           |B0
        andlw   b'11111111'     ;                                 |B0
        skpnz                   ; a 00 byte, last character?      |B0
        return                  ; yes, return                     |B0
        call    Put232          ; output char                     |B0
        incfsz  PTRL,F          ; increment pointer               |B0
        goto    PutString       ;                                 |B0
        incf    PTRH,F          ;                                 |B0
        goto    PutString       ;                                 |B0
;
GetTable
        movf    PTRH,W          ;                                 |B0
        movwf   PCLATH          ;                                 |B0
        movf    PTRL,W          ;                                 |B0
        movwf   PCL             ;                                 |B0
;
sHello  dt      0x1b, "[2J"     ;home & clear screen
        dt      "K8LH 16F88 EEPROM Test v1.0\r\n\n\n",0
;
        END
 

Attachments

  • curious.PNG
    curious.PNG
    13.1 KB · Views: 822
Last edited:
I see your problem... You never switch back to bank 0 before calling the EE routines. The EE routines assume that you're in bank 0 when they're called.

Banking is the number one headache on 12F' and 16F' devices. I usually write my programs using bank 0 as the default bank. That is, each subroutine relies on being in bank 0 when it's called and will make sure to switch back to bank 0 on exit. We all come up with different schemes. Just pick something that works for you and stick with it.

Mike
 
I found a bug, and changed it, the data should be written in EEDATA so I changed the code to read that. But I still don't get
0xAB data written in EEDATA.... ?!?!


OK Switch back to bank 0 after the TRISA call.... good point. What about the EEDATA register... is that OK or not?

Code:
LIST	p=16F88
	include "P16F88.inc"
	__config _CONFIG1, _WDT_OFF & _INTRC_IO & _MCLR_ON & _LVP_OFF
	ERRORLEVEL 0, -302

		goto start

EEPTR   equ      h'74'   ; EEPROM address pointer
NEW   	equ     h'75'   ; EEPROM data
OLD 	equ     h'76'	
;******************************************************************
;

;  entry: W contains data,  EEPTR contains address, 0..255
;
write
        movwf   NEW           ; save data                       
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              
        movf    EEPTR,W           ; get address                     
        movwf   EEADR           ; set address                     
        movf    NEW,W         ; get data                        
        movwf   EEDATA           ; set data                        
        bsf     STATUS,RP0      ; bank 3                          
        bcf     EECON1,EEPGD    ; select data memory              
        bsf     EECON1,WREN     ; enable writes                   
  
        movlw   h'55'           ;                                 
        movwf   EECON2          ;                                 
        movlw   h'AA'           ;                                 
        movwf   EECON2          ;                                 
        bsf     EECON1,WR       ; initiate the write              
Wr_chk
        btfsc   EECON1,WR       ; last write complete?            
        goto    Wr_chk          ; no, branch                      
       
        bcf     EECON1,WREN     ; disable writes                  
        bcf     STATUS,RP0      ; bank 2                          
        bcf     STATUS,RP1      ; bank 0                          

        return                  ;                                 
;******************************************************************
;
;
;
read
        bsf     STATUS,RP1      ; bank 2 (RP0 clear)              
        movf    EEPTR,W         ; get address                     
        movwf   EEADR   ; set address                     
        bsf     STATUS,RP0      ; bank 3                          
        bcf     EECON1,EEPGD    ; select data memory              
        bsf     EECON1,RD       ; perform RD operation            
        bcf     STATUS,RP0      ; bank 2                          
        movf    EEDATA,W        ; get data byte                   
        bcf     STATUS,RP1      ; bank 0                          
        return                  ;     



	start

		banksel		TRISA 		;bank 1
		movlw		0x72		;8MHz clock
		movwf		OSCCON
		
 		movlw		h'074
		movwf		EEPTR
		movlw		0xAB
		call 		write
		nop
		call 		read
		movwf		OLD
		nop
hang
		goto		hang
		end
 
Last edited:
Thanks, believe it or not, I'm enjoying this tremendously... :)
I should have gone into electronics when I was 5 years old. Whenever someone I know has a kid and I need to buy a gift, I like to buy these 75-1 electronic kits/games for them. They're cheap and there is no end to the amount of learning you can get out of these. It's the kind of gift that keeps on giving.

I find it's never too early to start them in electronics.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top