2014年3月31日 星期一

DIY香水移動電源

                             因測試需要買了10個香水移動電源套件回來自己DIY 如下圖
其實也不算甚麼DIY 就只是把 PCB 放入塑膠盒中,再放入一個18650電池蓋上白色蓋子即完成
不過,因好奇PCB上少了一個元件,經查證缺的那個元件是DW06D 作用是防止電池過度放電的功能,呀呀 ! 少了他會讓電池 壽命變短啊 ,這是甚麼居心 ?

缺DW06D的情形下 ,會放電到2.2V 這18650 鋰電池會被他害死的,需另外再購入DW06D自己來銲,這樣算一算 ,真省不了多少錢

市面上的香水或口紅移動電源,都是中國製的,我買的這個還留下一個陷阱,讓18650壽命變短真是....

2014年3月26日 星期三

資訊分享(2014-3-26)


希望對你有幫助

2014年3月25日 星期二

做了幾片PCB

之前都是用手銲的,終於作了一片專用板

這個USB燈有恆定電流控制,不是用電阻限流,用一個18650電池,可以連續點亮10小時 

火紅的 LM2596S DC2DC 降壓 

2014年3月24日 星期一

LED 混色



我這個是用TM1804 ,市面上的七彩燈條大部分是用WS2801不過都大同小異啦
一般玩七彩燈條會買專用的控制器,我這個只是玩玩所以用MCU 直驅TM1804 ,
這IC 的控制線只有一條 所以時序上要求較緊張,在第一張圖片裡有其時序規格 ,
MCU是用82E54 晶振24Mhz,所以1cycle是0.042uSec 其控制方式,下次再聊 

老MCU

PIC16F72好老的單片機不過比PIC16F5X好一些啦,多了ADC TIMER0 TIMER1 TIMER2中斷等,

       2K x 14字的程序存儲器,
      128×8個字節的數據存儲器(RAM)
       八級深硬件堆棧<< 堆疊只有8層
麻煩的是使用數據存儲要先切到正確的銀行,光看到這規格是不是就打退堂鼓了呢?
因為手上剛好有這芯片就順手測試一下,就當作是筆記下面練習程式啟動計時1中斷,
(這顆的中斷位置是所有中斷一起共用的,所以進到中斷副程式時要先檢查是哪一個中斷裝置發生中斷)令端口_A每進一次中斷就反向輸出一次

列表P = 16F72; 列表指令來定義處理器
#包括         ; 具體的處理器變量定義

__config _CP_OFF​​&_WDT_OFF&_BODEN_OFF&_PWRTE_ON&_XT_OSC

; “__config'指令用於內。asm文件中嵌入的配置數據。
; 下列指令的標籤都位於各自的。增量文件。
; 請參閱相關的數據表上的配置字的更多信息。

; *****變量定義(舉例)

W_TEMP EQU 32H
STATUS_TEMP EQU 31H
FLAG_A EQU 30H

; ****************** *********************
        ORG量0x000; 處理器復位向量
                轉到開始; 進入程序開始


INT_VECTOR:
        ORG量0x004; 中斷向量地址
MOVWF W_TEMP; 節省了電流W寄存器的內容;
MOVF 狀態,W; 移動狀態寄存器為W寄存器
BCF STATUS,RP0; 確保文件寄存器組設置為0
MOVWF STATUS_TEMP; 節省OFF狀態寄存器的內容


; ISR代碼可以去這裡或位於其他位置的子程序調用
               BANKSEL PIR1; TMR1IF
               BTFSS PIR1,0
               GOTO VECTOR_QUIT
               BCF PIR1,0; CLR TMR1IF
               COMF FLAG_A,0;取FLAG_A的補數
               MOVWF FLAG_A
               MOVLW B'11110000'; RELOAD TMR1H TMR1L
               MOVWF TMR1L
               MOVLW B'00000000'
               MOVWF TMR1H

VECTOR_QUIT:
      BCF STATUS,RP0; 確保文件寄存器組設置為0
      MOVF STATUS_TEMP,W; 找回狀態寄存器副本
      MOVWF 狀態; 恢復預ISR狀態寄存器的內容
      SWAPF W_TEMP,F
      SWAPF W_TEMP,W; 恢復預ISR W寄存器的內容
      RETFIE; 從中斷返回
開始:
        BANKSEL ADCON1; 16F72復位>> PORTA均設定為ADC
        MOVLW B'00000111'; PORTA至數字IO
        MOVWF ADCON1
        BANKSEL TRISA
        MOVLW B'00000000'
        MOVWF TRISA
        MOVWF TRISB
        MOVWF TRISC
        BANKSEL PORTA

        MOVLW 80H
        MOVWF PORTC
        MOVLW 0
        MOVWF 33H

    ; T1CON = 0B00110101;
        BANKSEL T1CON
        MOVLW B'00110101'
        MOVWF T1CON

 
    ; TIMER1為16BIT上數計數器
        MOVLW B'11110000'
        MOVWF TMR1L; 0X00F0
        MOVLW B'00000000'
        MOVWF TMR1H

   ; TMR1IE = 1; / /外設中斷使能
        BANKSEL PIE1
        MOVLW B'00000001'
        MOVWF PIE1

    ; PEIE = 1 ;/ /使能計時器1中斷
    ; GIE =​​ 1; / /全域中斷使能
        BANKSEL INTCON
        MOVLW B'11000000';
        MOVWF INTCON

LOOP:

         BTFSC FLAG_A,0
         GOTO OFF_LED
         MOVLW B'00000000';
         MOVWF PORTA
         GOTO LOOP
OFF_LED:
         MOVLW B'11111111';
         MOVWF PORTA
         GOTO LOOP

         完

2014年3月11日 星期二

趨勢

很久以前曾購買"時鐘4位led",找東西時不小心浮上桌面,隨手銲一片洞洞板,線路如上圖,然後分別在89E58,Atmega16,Nuc100執行一樣功能的程序
笙泉89E58

atmel的Atmega16


新唐NUC100
由下面3支程序可看出,C 在跨平台上,真的很方便 主程式並沒有做甚麼改變,不同處只有各自的TIMER設定,GPIO設定及位(BIT)操作,我一直以來都是用8X51組合語言在寫程序,偶而用PIC16F5X組合語言,自從接觸到 LPC2103(ARM7)後,強烈感覺用C真的比組合語言輕鬆很多,深刻感覺大勢所趨 呵呵 ,另外 一個趨勢"ARDUINO"這個板子,對初學者應該很便利,個人感到快被"ARDUINO"淹沒, Atmel Atmega系列因"ARDUINO"而得以熱銷,對Atmel 是件好事, 但感覺好像有點怪怪的,你有感覺到嗎?
//89e58程序 IDE  KEIL C
//  Function:時鐘計時
//  基板:      
#include "REG_MPC89L51-515.H"
#include "INTRINS.H"
  // io port Description
#define _ONE    P10  //個
#define _TWO    P11  //拾
#define _THREE  P12  //百
#define _FOUR   P13  //千
#define KEY     P42

const _7_seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90,0xff }; 
unsigned char time_cnt,min_cnt=43,hour_cnt=12,show_time=0;
unsigned char _1_sec_cnt=0x28 ; //一秒 計時
unsigned char  scan_cnt=0X00;   //顯示掃瞄的位數指標
unsigned char disp_0,disp_1,disp_2,disp_3;
bit  _05sec,hour_sw=0;

//-------------------------------------------------
void Init_IRQ()
{

    ET1     =   0x01; //Enable Timer Interrupt 1
    TMOD    =  0X10 ;
    TH1     =  0X3C ;          
    TL1     =  0XB0 ; 
    EA      =  0x01 ; //Enable All Interrupt                    
    TR1     =  0X01 ; //START TIMER1
  
}

void Timer_Interrupt_1() interrupt 3
{
    _1_sec_cnt -- ;
   if (_1_sec_cnt==0)       // 計算 1秒
    {  time_cnt ++ ;
       _1_sec_cnt=0x28 ;
    }
     
   if(_1_sec_cnt>=0x14)     // 產生0.5 Sec
        {_05sec=1;}
   else {_05sec=0;}

   if (time_cnt>=60)    //每60秒進一
    { min_cnt+=1;
          time_cnt=0; 
         } 
   if (min_cnt>=60)    //每60分進一
    { hour_cnt+=1;
          min_cnt=0; 
         } 

     TH1    =  0X3C ;          
     TL1    =  0XB0 ; 
}

main()
{
    Init_IRQ();
//-----------------------------------------------
while (1)
{
     if (scan_cnt>3) scan_cnt=0x00;


     switch(scan_cnt)
       {case 0:
                    P2=0XFF;
                    _ONE=0x00;
                    _TWO=0x01;
                    _THREE=0X01;
                    _FOUR=0X01;
                    if (05sec==1) {P2= _7_seg[disp_0]&0x7f;}
                     else {P2= _7_seg[disp_0]|0x80;}
                //    P2= _7_seg[disp_0] ;
               scan_cnt ++ ;
                    break;

        case 1:
                     P2=0XFF;
                    _ONE=0x01;
                    _TWO=0x00;
                    _THREE=0X01;
                    _FOUR=0X01;
                    if (05sec==1) {P2= _7_seg[disp_1]&0x7f;}
                     else {P2= _7_seg[disp_1]|0x80;}
                 //   P2= _7_seg[disp_1] ;
                    scan_cnt ++ ;
                    break;
                    
        case 2:
                    P2=0XFF;
                    _ONE=0x01;
                    _TWO=0x01;
                    _THREE=0X00;
                    _FOUR=0X01;

                    P2= _7_seg[disp_2] ; 
                    scan_cnt ++ ;
                    break;
        case 3:
                    P2=0XFF;
                    _ONE=0x01;
                    _TWO=0x01;
                    _THREE=0X01;
                    _FOUR=0X00;

                    P2= _7_seg[disp_3] ;  
                    scan_cnt ++ ;
                    break;
        } 
                    disp_0 = time_cnt % 10 ;  
                    disp_1 = (time_cnt/10)%10 ;  
    
                    disp_2= (min_cnt%10); 
                    disp_3 = (min_cnt/10)%10 ; 
                           
         }
  
}
//----------------------------------------------------------------------------------------
//Atmega16  IDE AVR studio4.18
#include "avr/interrupt.h"
#include "avr/iom16.h"
#include "avr/io.h"

const unsigned char _7_seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90,0xff };
unsigned char time_cnt,min_cnt=43,hour_cnt=12,show_time=0;
unsigned char _1_sec_cnt=0x28 ; //一秒 計時
unsigned char  scan_cnt=0X00;   //顯示掃瞄的位數指標
unsigned char disp_0,disp_1,disp_2,disp_3;
//USER_FLAG_a------------------
unsigned char  flag_a=0x00;
unsigned char  _05sec=1;

#define _ONE_OFF     PORTB|=_BV(4)    //個
#define _ONE_ON      PORTB&=~_BV(4)
#define _TWO_OFF     PORTB|=_BV(3)    //拾
#define _TWO_ON      PORTB&=~_BV(3)
#define _THREE_OFF   PORTB|=_BV(2)    //百
#define _THREE_ON    PORTB&=~_BV(2)
#define _FOUR_OFF    PORTB|=_BV(1)    //千
#define _FOUR_ON     PORTB&=~_BV(1)

ISR (TIMER0_OVF_vect)
{
 TCNT0 = 0x3D; //reload counter value
   _1_sec_cnt -- ;

   if (_1_sec_cnt==0)       // 計算 1秒
    {  time_cnt ++ ;
       _1_sec_cnt=0x28 ;
    }
   if(_1_sec_cnt>=0x14)     // 產生0.5 Sec
          { flag_a|=_BV(_05sec);}
   else
         {flag_a&=~_BV(_05sec);}

    if (time_cnt>=60)    //每60秒進一
    { min_cnt+=1;
          time_cnt=0;
         }
   if (min_cnt>=60)    //每60分進一
    { hour_cnt+=1;
          min_cnt=0;
         }
}

void timer0_init(void)
{
      TCCR0 = 0x00;  //stop
      TCNT0 = 0x3D;  //set count
      OCR0  = 0xC3;  //set compare
      TCCR0 = 0x05;  //start timer
}

int main(void)
{
        DDRA=0Xff;
        PORTA=0Xff;

        DDRB=0Xff;
        PORTB=0Xff;
       //stop errant interrupts until set up
        cli(); //disable all interrupts

        timer0_init();

        MCUCR = 0x00;
        GICR  = 0x00;
        TIMSK = 0x01;  //timer interrupt sources
        sei();         //re-enable interrupts
 //all peripherals are now initialized

while (1)
{
     if (scan_cnt>3) scan_cnt=0x00;

     switch(scan_cnt)
       {case 0:
                   PORTA=0XFF;
                    _ONE_ON;
                    _TWO_OFF;
                    _THREE_OFF;
                    _FOUR_OFF;

                    if (bit_is_set(flag_a,_05sec)) {PORTA= _7_seg[disp_0]&0x7f;}
                     else {PORTA= _7_seg[disp_0]|0x80;}

                  //  PORTA= _7_seg[disp_0] ;
               scan_cnt ++ ;
                    break;

        case 1:
                    PORTA=0XFF;
                    _ONE_OFF;
                    _TWO_ON;
                    _THREE_OFF;
                    _FOUR_OFF;

                    if (bit_is_set(flag_a,_05sec)) {PORTA= _7_seg[disp_1]&0x7f;}
                     else {PORTA= _7_seg[disp_1]|0x80;}
                 //   led_segment= _7_seg[disp_1] ;
                    scan_cnt ++ ;
                    break;
                 
        case 2:
                    PORTA=0XFF;
                    _ONE_OFF;
                    _TWO_OFF;
                    _THREE_ON;
                    _FOUR_OFF;

                   PORTA= _7_seg[disp_2] ;

                    scan_cnt ++ ;
                    break;
        case 3:
                    PORTA=0XFF;
                    _ONE_OFF;
                    _TWO_OFF;
                    _THREE_OFF;
                    _FOUR_ON;

                    PORTA= _7_seg[disp_3] ;
                    scan_cnt ++ ;
                    break;
        }
                    disp_0 = time_cnt % 10 ;
                    disp_1 = (time_cnt/10)%10 ;
                    disp_2= (min_cnt%10);
                    disp_3 = (min_cnt/10)%10 ;

}
}
//-------------------------------------------------------------------------------
//新唐 Cortex M0  NUC100  IDE MDK KEIL 4.2
#include
#include "NUC1xx.h"
#include "Driver\DrvGPIO.h"
#include "Driver\DrvSYS.h"

#define led_segment GPB_DOUT
#define _ONE    GPIOA->DOUT.DOUT4   //個
#define _TWO    GPIOA->DOUT.DOUT5   //拾
#define _THREE  GPIOA->DOUT.DOUT6   //百
#define _FOUR   GPIOA->DOUT.DOUT7   //千   
          
#define  BIBI     DOUT8
#define ON_BIBI  GPIOB->DOUT.BIBI=0
#define OFF_BIBI GPIOB->DOUT.BIBI=1
#define  KEY0     PIN15
const char _7_seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90,0xff }; 
unsigned char time_cnt,min_cnt=43,hour_cnt=12,show_time=0;
unsigned char _1_sec_cnt=0x28 ; //一秒 計時
unsigned char  scan_cnt=0X00;   //顯示掃瞄的位數指標
unsigned char disp_0,disp_1,disp_2,disp_3;

typedef struct
{
         
        struct 
        {
            __IO uint32_t  bibi_1:1;
            
            __IO uint32_t  _05sec:1;            
            __IO uint32_t  hour_sw:1;            
            __I  uint32_t  RESERVE:29;
        } Config;
   
} UART_FLAG_T;
UART_FLAG_T User1;

// User1.Config.hit_one = 1;
signed char dump_num=0,bi_time=5;
unsigned char cnt0=0,cnt1=0,cnt2=0,auto_hit=0;
unsigned char cnt02=0,cnt12=0,cnt22=0,auto_hit2=0;
volatile uint32_t FLAG_0=0;

void TMR0_IRQHandler(void) // Timer0 interrupt subroutine 
  TIMER0->TISR.TIF =1;
////////////////////////////////////////
   if (User1.Config.bibi_1==1)
       { bi_time--;
         if(bi_time<=0)
           {User1.Config.bibi_1=0;
            bi_time=5;
            OFF_BIBI ;
           }
         else
           {ON_BIBI; } 
}

    _1_sec_cnt -- ;
   if (_1_sec_cnt==0)       // 計算 1秒
    {  time_cnt ++ ;
       _1_sec_cnt=0x28 ;
    }
     
   if(_1_sec_cnt>=0x14)     // 產生0.5 Sec
        {User1.Config._05sec=1;}
   else {User1.Config._05sec=0;}

   if (time_cnt>=60)    //每60秒進一
    { min_cnt+=1;
          time_cnt=0; 
         } 
   if (min_cnt>=60)    //每60分進一
    { hour_cnt+=1;
          min_cnt=0; 
         } 
 // TIMER0->TISR.TIF =1;
}
//
void Timer_initial(void)
{
/* Step 1. Enable and Select Timer clock source */ 
     /* 切換IP模組的時鐘源 */   
SYSCLK->CLKSEL1.TMR0_S = 0; //Select 12Mhz for Timer0 clock source 
        SYSCLK->APBCLK.TMR0_EN =1; //Enable Timer0 clock source

/* Step 2. Select Operation mode */
TIMER0->TCSR.MODE=1; //Select periodic mode for operation mode

/* Step 3. Select Time out period = (Period of timer clock input) * (8-bit Prescale + 1) * (24-bit TCMP)*/
TIMER0->TCSR.PRESCALE=0;   // Set Prescale [0~255]
TIMER0->TCMPR  = 300000  ; // Set TICR(TCMP) [0~16777215]
          // (1/12000000)*(0+1)*(300000)= 250usec 
/* Step 4. Enable interrupt */
TIMER0->TCSR.IE = 1;
TIMER0->TISR.TIF = 1; //Write 1 to clear for safty
NVIC_EnableIRQ(TMR0_IRQn); //Enable Timer0 Interrupt

/* Step 5. Enable Timer module */
TIMER0->TCSR.CRST = 1; //Reset up counter
TIMER0->TCSR.CEN = 1; //Enable Timer0

  TIMER0->TCSR.TDR_EN=1; // 
}

/*-----------*/
/*  Main Function  */
/*-----------*/
int main(void)
{
//volatile int32_t i32delay=1000;
/* SYSCLK =>12Mhz*/
UNLOCKREG();

  
    SYSCLK->PWRCON.XTL12M_EN = 1 ;

  while(SYSCLK->CLKSTATUS.XTL12M_STB==0);

SYSCLK->CLKSEL0.HCLK_S=0;
SYSCLK->CLKSEL0.STCLK_S=0;
//------------------------------------
    GPIOA-> PMD.PMD4 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOA-> PMD.PMD5 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOA-> PMD.PMD6 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOA-> PMD.PMD7 = 0X03;   // 設為雙向,和51_IO 相同
    
    GPIOB-> PMD.PMD0 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOB-> PMD.PMD1 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOB-> PMD.PMD2 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOB-> PMD.PMD3 = 0X03;   // 設為雙向,和51_IO 相同

    GPIOB-> PMD.PMD4 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOB-> PMD.PMD5 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOB-> PMD.PMD6 = 0X03;   // 設為雙向,和51_IO 相同
    GPIOB-> PMD.PMD7 = 0X03;   // 設為雙向,和51_IO 相同

//--設定time0 啟動time0中斷
     Timer_initial();
//--設定time0 啟動time0中斷    
     
 GPB_DMASK=0xff00;
 User1.Config.bibi_1=0;  
 while (1)
  {

     if (scan_cnt>3) scan_cnt=0x00;
     switch(scan_cnt)
       {case 0:
                   led_segment=0XFF; 
                    _ONE=0x00;
                    _TWO=0x01;
                    _THREE=0X01;
                    _FOUR=0X01;

               
                    if(User1.Config._05sec==1){led_segment= _7_seg[disp_0]&0x7f;} //
                     else {led_segment= _7_seg[disp_0]|0x80;}

                //    led_segment= _7_seg[disp_0] ;
               scan_cnt ++ ;
                    break;

        case 1:
                    led_segment=0XFF;
                    _ONE=0x01;
                    _TWO=0x00;
                    _THREE=0X01;
                    _FOUR=0X01;

                    if(User1.Config._05sec==1){led_segment= _7_seg[disp_1]&0x7f;} // 
                     else {led_segment= _7_seg[disp_1]|0x80;}
                //    led_segment= _7_seg[disp_1] ;
                    scan_cnt ++ ;
                    break;
                    
        case 2:
                    led_segment=0XFF;
                    _ONE=0x01;
                    _TWO=0x01;
                    _THREE=0X00;
                    _FOUR=0X01;

                   led_segment= _7_seg[disp_2] ; 

                    scan_cnt ++ ;
                    break;
        case 3:
                    led_segment=0XFF;
                    _ONE=0x01;
                    _TWO=0x01;
                    _THREE=0X01;
                    _FOUR=0X00;

                    led_segment= _7_seg[disp_3] ;  
                    scan_cnt ++ ;
                    break;
        } 
                    disp_0 = time_cnt % 10 ;  
                    disp_1 = (time_cnt/10)%10 ;  
    
                    disp_2= (min_cnt%10); 
                    disp_3 = (min_cnt/10)%10 ; 
                     
  }
 }