2014年1月23日 星期四

STM8S-Discovery_STM8S003F3-5_UART使用printf()

    之前建立一個新的project是使用STM8105C6這顆MCU,不過因為某些原因所以換成STM8103F3,這兩顆在中斷位置與暫存器位置上有些許差異,所以程式在不同MCU移植時,請先檢查比對Datasheet的Register map(修改stm8s_003x.h)與Interrupt vector mapping(修改stm8_interrupt_vector.c).

    STM8S的編譯器Comic支援system call所以UART初始化後,UART的Tx可以直接使用printf(),那Rx可以使用char getinput(void);函數或是讀取flag的值.

1. 整個project的程式檔案目錄如下圖所示.

2.  main.c
/***********************************************/
#include "stm8s_003x.h"
#include "stm8s_type.h"
#include "uart.h"
#include <stdio.h>

u8 i = 10;
int main(void)
{
  UART_CLKInit();
  UART_GPIOInit();
  UART1_Init();

enableInterrupts(); //InterruptInit

printf("Hello World.\n\r");
printf("Value = %d \n\r", i);

return 0;
}

@far @interrupt void UART1_RX_IRQHandler (void)
{
  flag = UART1->DR;  //Auto clear RXNE bit

  UART1->SR &= 0xDF; //Clear RXNE by write 0 to it
}

@far @interrupt void UART1_TX_IRQHandler (void)
{
flag = UART1->DR;
}
/***********************************************/

3. stm8_interrupt_vector.c
/***********************************************/
/* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
 * Copyright (c) 2007 STMicroelectronics
 */

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
unsigned char interrupt_instruction;
interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
/* in order to detect unexpected events during development,
  it is recommended to set a breakpoint on the following instruction
*/
return;
}

extern void _stext();     /* startup routine */
extern @far @interrupt void UART1_TX_IRQHandler (void);
extern @far @interrupt void UART1_RX_IRQHandler (void);


struct interrupt_vector const _vectab[] = {
{0x82, (interrupt_handler_t)_stext}, /* reset */
{0x82, NonHandledInterrupt}, /* trap  */
{0x82, NonHandledInterrupt}, /* irq0  */
{0x82, NonHandledInterrupt}, /* irq1  */
{0x82, NonHandledInterrupt}, /* irq2  */
{0x82, NonHandledInterrupt}, /* irq3  */
{0x82, NonHandledInterrupt}, /* irq4  */
{0x82, NonHandledInterrupt}, /* irq5  */
{0x82, NonHandledInterrupt}, /* irq6  */
{0x82, NonHandledInterrupt}, /* irq7  */
{0x82, NonHandledInterrupt}, /* irq8  */
{0x82, NonHandledInterrupt}, /* irq9  */
{0x82, NonHandledInterrupt}, /* irq10 */
{0x82, NonHandledInterrupt}, /* irq11 */
{0x82, NonHandledInterrupt}, /* irq12 */
{0x82, NonHandledInterrupt}, /* irq13 */
{0x82, NonHandledInterrupt}, /* irq14 */
{0x82, NonHandledInterrupt}, /* irq15 */
{0x82, NonHandledInterrupt}, /* irq16 */
{0x82, (interrupt_handler_t)UART1_TX_IRQHandler}, /* irq17 */
{0x82, (interrupt_handler_t)UART1_RX_IRQHandler}, /* irq18 */
{0x82, NonHandledInterrupt}, /* irq19 */
{0x82, NonHandledInterrupt}, /* irq20 */
{0x82, NonHandledInterrupt}, /* irq21 */
{0x82, NonHandledInterrupt}, /* irq22 */
{0x82, NonHandledInterrupt}, /* irq23 */
{0x82, NonHandledInterrupt}, /* irq24 */
{0x82, NonHandledInterrupt}, /* irq25 */
{0x82, NonHandledInterrupt}, /* irq26 */
{0x82, NonHandledInterrupt}, /* irq27 */
{0x82, NonHandledInterrupt}, /* irq28 */
{0x82, NonHandledInterrupt}, /* irq29 */
};
/***********************************************/

4. uart.c
/***********************************************/
#include "stm8s_003x.h"
#include "stm8s_type.h"

void UART_CLKInit(void) //initialize the registers of Clock 
{
  CLK->ECKR |= 0x01; //enable extern clock,only ECKR_HSEEN = 1 
  
  CLK->CKDIVR = 0x00; //set prescaler
  
  CLK->PCKENR1 |= 0x08; //enable peripheral clock, only CLK_PCKENR1_3 = 1; 
}

void UART_GPIOInit() //initialize the registers of GPIO
{
  GPIOD->DDR |= 0x20; //PD5 output, PD6 input
  
  GPIOD->CR1 |= 0x20; //output : push-pull mode ; input: float mode
  
  GPIOD->CR2 |= 0x20; //output at 10 Mhz
}

void UART1_Init(void) //initialize the registers of uart2
{
  
//  UART1->BRR2 = 0x02; //set baud rate at 1200 ; mainClock : 16 000 000   
//  UART1->BRR1 = 0x68;
UART1->BRR2 = 0x08; //set baud rate at 19200 ; mainClock : 16 000 000  
  UART1->BRR1 = 0x06;
  UART1->CR1 = 0x00; //NO parity PCEN=0,8 data bits M=0,enable UART2 UARTD=0
    
  UART1->CR2 = 0x2C; //wait for you; enable TX and RX TEN=0,REN=0;enable receive interrupt RIEN=1
    
  UART1->CR3 = 0x00; //one stop bits
}

void SendByte(u8 temp) //send one byte by the UART2
{
  while(((UART1->SR)&0x80) != 0x80); //estimate if send OK
UART1->DR = temp;
}

char putchar(char c) //Retargets the C library printf function to the UART2
{
  SendByte((u8)c); //Write a character to the UART1 
  while((UART1->SR & 0x40) != 0x40); //Loop until the end of transmission 
  UART1->SR &= 0xBF; //clear TC bit by write 0 to it
    
  return(c);
}

char getinput(void)
{
volatile char input;
return(input);
}
/***********************************************/

5. stm8s_003x.h
/***********************************************/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8_003x_H
#define __STM8_003x_H

#include "stm8s_type.h"
/******************************************************************************/
/*                   Library configuration section                            */
/******************************************************************************/

/******************************************************************************/
/*                          Peripherals Base Address                          */
/******************************************************************************/
#define GPIOA_BaseAddress       0x5000
#define GPIOB_BaseAddress       0x5005
#define GPIOC_BaseAddress       0x500A
#define GPIOD_BaseAddress       0x500F
#define GPIOE_BaseAddress       0x5014
#define GPIOF_BaseAddress       0x5019
#define FLASH_BaseAddress       0x505A
#define ITC_BaseAddress         0x50A0
#define RST_BaseAddress         0x50B3
#define CLK_BaseAddress         0x50C3
#define WWDG_BaseAddress       0x50D1
#define IWDG_BaseAddress       0x50E0
#define AWU_BaseAddress         0x50F0
#define BEEP_BaseAddress        0x50F3
#define SPI_BaseAddress         0x5200
#define I2C_BaseAddress         0x5210
#define UART1_BaseAddress       0x5230
#define TIM1_BaseAddress        0x5250
#define TIM2_BaseAddress        0x5300
#define TIM4_BaseAddress        0x5340
#define ADC1_BaseAddress        0x53E0


/******************************************************************************/
/*                          Peripherals declarations                          */
/******************************************************************************/

#define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BaseAddress)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BaseAddress)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BaseAddress)
#define GPIOF  ((GPIO_TypeDef *)  GPIOF_BaseAddress)
#define FLASH ((FLASH_TypeDef *) FLASH_BaseAddress)
#define ITC ((ITC_TypeDef *) ITC_BaseAddress)
#define RST ((RST_TypeDef *) RST_BaseAddress)
#define CLK ((CLK_TypeDef *) CLK_BaseAddress)
#define WWDG ((WWDG_TypeDef *) WWDG_BaseAddress)
#define IWDG ((IWDG_TypeDef *) IWDG_BaseAddress)
#define AWU ((AWU_TypeDef *) AWU_BaseAddress)
#define BEEP ((BEEP_TypeDef *) BEEP_BaseAddress)
#define SPI ((SPI_TypeDef *) SPI_BaseAddress)
#define I2C ((I2C_TypeDef *) I2C_BaseAddress)
#define UART1 ((UART1_TypeDef *) UART1_BaseAddress)
#define TIM1 ((TIM1_TypeDef *) TIM1_BaseAddress)
#define TIM2 ((TIM2_TypeDef *) TIM2_BaseAddress)
#define TIM4 ((TIM4_TypeDef *) TIM4_BaseAddress)
#define ADC1 ((ADC1_TypeDef *) ADC1_BaseAddress)

/******************************************************************************/
/*                          IP registers structures                           */
/******************************************************************************/

#define enableInterrupts() {_asm("rim\n");} /* enable interrupts */
#define disableInterrupts() {_asm("sim\n");} /* disable interrupts */
/* @brief General Purpose I/Os (GPIO) */
typedef struct GPIO_struct
{
vu8 ODR; /*!< Output Data Register */
  vu8 IDR; /*!< Input Data Register */
  vu8 DDR; /*!< Data Direction Register */
  vu8 CR1; /*!< Configuration Register 1 */
  vu8 CR2; /*!< Configuration Register 2 */
}GPIO_TypeDef;

/* @brief Clock Controller (CLK) */

typedef struct CLK_struct
{
  vu8 ICKR;     /*!< Internal Clocks Control Register */
  vu8 ECKR;     /*!< External Clocks Control Register */
  u8 RESERVED; /*!< Reserved byte */
  vu8 CMSR;     /*!< Clock Master Status Register */
  vu8 SWR;      /*!< Clock Master Switch Register */
  vu8 SWCR;     /*!< Switch Control Register */
  vu8 CKDIVR;   /*!< Clock Divider Register */
  vu8 PCKENR1;  /*!< Peripheral Clock Gating Register 1 */
  vu8 CSSR;     /*!< Clock Security Sytem Register */
  vu8 CCOR;     /*!< Configurable Clock Output Register */
  vu8 PCKENR2;  /*!< Peripheral Clock Gating Register 2 */
  vu8 CANCCR;   /*!< CAN external clock control Register (exist only in STM8S208 otherwise it is reserved) */
  vu8 HSITRIMR; /*!< HSI Calibration Trimmer Register */
  vu8 SWIMCCR;  /*!< SWIM clock control register */
}CLK_TypeDef;

/* @brief Universal Synchronous Asynchronous Receiver Transmitter (UART1) */

typedef struct UART1_struct
{
  vu8 SR;   /*!< UART1 status register */
  vu8 DR;   /*!< UART1 data register */
  vu8 BRR1; /*!< UART1 baud rate register */
  vu8 BRR2; /*!< UART1 DIV mantissa[11:8] SCIDIV fraction */
  vu8 CR1;  /*!< UART1 control register 1 */
  vu8 CR2;  /*!< UART1 control register 2 */
  vu8 CR3;  /*!< UART1 control register 3 */
  vu8 CR4;  /*!< UART1 control register 4 */
  vu8 CR5;  /*!< UART1 control register 5 */
vu8 CR6;  /*!< UART1 control register 6 */
  vu8 GTR;  /*!< UART1 guard time register */
  vu8 PSCR; /*!< UART1 prescaler register */
}UART1_TypeDef;


#endif /* __STM8S_003x_H */

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/

/***********************************************/

6. stm8s_type.h
/***********************************************/
/**
  ******************************************************************************
  * @file stm8s_type.h
  * @brief This file contains all common data types.
  * @author STMicroelectronics - MCD Application Team
  * @version V1.1.1
  * @date 06/05/2009
  ******************************************************************************
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  * @image html logo.bmp
  ******************************************************************************
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_TYPE_H
#define __STM8S_TYPE_H

/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef signed long  s32;
typedef signed short s16;
typedef signed char  s8;

typedef signed long  const sc32;  /* Read Only */
typedef signed short const sc16;  /* Read Only */
typedef signed char  const sc8;   /* Read Only */

typedef volatile signed long  vs32;
typedef volatile signed short vs16;
typedef volatile signed char  vs8;

typedef volatile signed long  const vsc32;  /* Read Only */
typedef volatile signed short const vsc16;  /* Read Only */
typedef volatile signed char  const vsc8;   /* Read Only */

typedef unsigned long  u32;
typedef unsigned short u16;
typedef unsigned char  u8;

typedef unsigned long  const uc32;  /* Read Only */
typedef unsigned short const uc16;  /* Read Only */
typedef unsigned char  const uc8;   /* Read Only */

typedef volatile unsigned long  vu32;
typedef volatile unsigned short vu16;
typedef volatile unsigned char  vu8;

typedef volatile unsigned long  const vuc32;  /* Read Only */
typedef volatile unsigned short const vuc16;  /* Read Only */
typedef volatile unsigned char  const vuc8;   /* Read Only */

typedef enum
{
  FALSE = 0,
  TRUE = !FALSE
}bool;

typedef enum 
{
  RESET = 0,
  SET = !RESET
}FlagStatus, ITStatus, BitStatus;

typedef enum
{
  DISABLE = 0,
  ENABLE = !DISABLE
}FunctionalState;

#define IS_FUNCTIONALSTATE_OK(VALUE) ( (VALUE == ENABLE) || (VALUE == DISABLE) )

typedef enum
{
  ERROR = 0,
  SUCCESS = !ERROR
}ErrorStatus;

#define U8_MAX     ((u8)255)
#define S8_MAX     ((s8)127)
#define S8_MIN     ((s8)-128)
#define U16_MAX    ((u16)65535u)
#define S16_MAX    ((s16)32767)
#define S16_MIN    ((s16)-32768)
#define U32_MAX    ((u32)4294967295uL)
#define S32_MAX    ((s32)2147483647)
#define S32_MIN    ((s32)-2147483648)

/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */

#endif /* __STM8S_TYPE_H */

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/

/***********************************************/

7. uart.h
/***********************************************/
#include "stm8s_type.h"

void UART_CLKInit(void);
void UART_GPIOInit(void);
void UART1_Init(void);
void SendByte(u8 temp);
char putchar(char c);
char getinput(void);

u8 flag = 0;
/***********************************************/

34 則留言:

  1. 你好,我剛接觸STM8S,使用STVD+cosmic開發,目前遇到一個問題,就是用timer4中斷,用start debugging之後發現它一直在中斷副程式RUN而跳不出去,請問是哪裡出了問題?我的程式如下
    main.c
    /* MAIN.C file
    *
    * Copyright (c) 2002-2005 STMicroelectronics
    */
    #include "iostm8s.h"

    void delayms(unsigned int ms)
    {
    unsigned char i;
    while(ms != 0)
    {
    for(i=0;i<250;i++)
    {
    }
    for(i=0;i<75;i++)
    {
    }
    ms--;
    }
    }

    main()
    {
    CLK_SWR=0xe1;
    //CLK_CKDIVR=0x08;
    PA_DDR=0b00001110;
    PA_CR1=0b00001110;
    PA_CR2=0x00;
    PB_DDR=0b00100000;
    PB_CR1=0b00100000;
    PB_CR2=0x00;
    PC_DDR=0b00101000;
    PC_CR1=0b00101000;
    PC_CR2=0x00;
    PD_DDR=0b00000110;
    PD_CR1=0b00000110;
    PD_CR2=0x00;
    //TMR4 setting
    TIM4_IER=0x00;
    TIM4_EGR=0x01;
    TIM4_PSCR=0x07;
    TIM4_ARR=255;
    TIM4_CNTR=255;
    TIM4_CR1=0x01;
    TIM4_IER=0x01;
    //TMR4 setting
    _asm("rim"); //Enable interrupt (level 0 set)
    while (1)
    {
    //PA_ODR=PA_ODR | 0b00001110;
    //delayms(200);
    //PA_ODR=PA_ODR & 0b11110001;
    PB_ODR=PB_ODR | 0b00100000;
    //delayms(200);
    PB_ODR=PB_ODR & 0b11011111;
    PC_ODR=PC_ODR | 0b00101000;
    //delayms(200);
    PC_ODR=PC_ODR & 0b11010111;
    //delayms(200);
    PD_ODR=PD_ODR | 0b00000110;
    //delayms(200);
    PD_ODR=PD_ODR & 0b11111001;
    }
    }
    @far @interrupt void tmr4_interrupt(void)
    {
    TIM4_SR=0x00;
    PA_ODR=PA_ODR ^ 0x02;
    //return;
    }

    stm8s_interrupt_vector.c
    /* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
    * Copyright (c) 2007 STMicroelectronics
    */

    typedef void @far (*interrupt_handler_t)(void);

    struct interrupt_vector {
    unsigned char interrupt_instruction;
    interrupt_handler_t interrupt_handler;
    };

    @far @interrupt void NonHandledInterrupt (void)
    {
    /* in order to detect unexpected events during development,
    it is recommended to set a breakpoint on the following instruction
    */
    //PA_ODR=PA_ODR ^ 0x02;
    return;
    }

    extern void main();//_stext(); /* startup routine */
    extern @far @interrupt void tmr4_interrupt(void);
    //extern @interrupt void tmr4_interrupt(void);

    struct interrupt_vector const _vectab[] = {
    {0x82, (interrupt_handler_t)main},//_stext}, /* reset */
    {0x82, NonHandledInterrupt}, /* trap */
    {0x82, NonHandledInterrupt}, /* irq0 */
    {0x82, NonHandledInterrupt}, /* irq1 */
    {0x82, NonHandledInterrupt}, /* irq2 */
    {0x82, NonHandledInterrupt}, /* irq3 */
    {0x82, NonHandledInterrupt}, /* irq4 */
    {0x82, NonHandledInterrupt}, /* irq5 */
    {0x82, NonHandledInterrupt}, /* irq6 */
    {0x82, NonHandledInterrupt}, /* irq7 */
    {0x82, NonHandledInterrupt}, /* irq8 */
    {0x82, NonHandledInterrupt}, /* irq9 */
    {0x82, NonHandledInterrupt}, /* irq10 */
    {0x82, NonHandledInterrupt}, /* irq11 */
    {0x82, NonHandledInterrupt}, /* irq12 */
    {0x82, NonHandledInterrupt}, /* irq13 */
    {0x82, NonHandledInterrupt}, /* irq14 */
    {0x82, NonHandledInterrupt}, /* irq15 */
    {0x82, NonHandledInterrupt}, /* irq16 */
    {0x82, NonHandledInterrupt}, /* irq17 */
    {0x82, NonHandledInterrupt}, /* irq18 */
    {0x82, NonHandledInterrupt}, /* irq19 */
    {0x82, NonHandledInterrupt}, /* irq20 */
    {0x82, NonHandledInterrupt}, /* irq21 */
    {0x82, NonHandledInterrupt}, /* irq22 */
    {0x82, (interrupt_handler_t)tmr4_interrupt}, /* irq23 */
    {0x82, NonHandledInterrupt}, /* irq24 */
    {0x82, NonHandledInterrupt}, /* irq25 */
    {0x82, NonHandledInterrupt}, /* irq26 */
    {0x82, NonHandledInterrupt}, /* irq27 */
    {0x82, NonHandledInterrupt}, /* irq28 */
    {0x82, NonHandledInterrupt}, /* irq29 */
    };

    回覆刪除
  2. Hi Gary Goole:
    這是因為你在一開始Time4的"TIM4_CR1=0x01;"就enable,所以Time4會不停的計數,而執行到了Time4中斷時,

    @far @interrupt void tmr4_interrupt(void)
    {
    TIM4_SR=0x00

    又將Time4重置,MCU內部的的時脈(Clock)不會因為你進入Debug mode就停止下來,所以你進入Debug mode時,你按一次單步的動作,Time4早就計數完畢,所以你就會覺得一直停留在中斷副程式中.

    回覆刪除
    回覆
    1. 你好,感謝你的解答,我會用debug mode就是因為main.c主程式裡的其他指令都沒有執行,我才會用debug mode去除錯,我用示波器看PA1的狀態Hi,Lo狀態個約9us,這是什麼原因讓程式一直在中斷副程式RUN而沒有跳到main主程式,希望你能解答我的困惑?

      刪除
    2. Hi Gary Goole:
      請教您是學生還是已經在上班的工程師,我想了解一下,因為是學生的話可能就要給您說明詳細一點,如果是工程師您可能要先了解一下,Time在IC內部硬體的工作原理,這樣會對你在使用Time4上會比較有幫助.

      您在enable Time4後,程式中斷優先權是Time4,所以Time4會優先執行,而你在Time4中斷裡只是將值重置,之後的程式並沒有關閉Time4,因此程式會重複執行Time4的中斷程序,要在Debug mode看到從Time4中斷程序中跳出來,就要將Time4 Disable.

      我給您先寫段範例,請將您的程式增加到//Add your program features.

      void TIM4_Init(void)
      {
      CLK->PCKENR1 &= 0x10; // TIM4 clock enable

      TIM4->ARR = 0x80; // Init time4 1ms interrupts
      TIM4->PSCR = 7; //Prescaler value
      TIM4->IER = 1; //Update interrupt enabled
      //TIM4->CR1 = 0x01; //Counter enable
      TIM4->CR1 = 0x00; //Counter disable
      }

      int main(void)
      {
      TIM4_Init();

      enableInterrupts(); //InterruptInit

      while(1)
      {
      TIM4->CR1 = 0x01; //Counter enable
      //Add your program features.
      TIM4->CR1 = 0x00; //Counter disable
      }
      return 0;
      }

      @far @interrupt void TIM4InterruptHandle (void)
      {
      TIM4->SR = 0; //Status register
      //TIF: No trigger event has occurred
      //UIF: No update has occurred
      //Add your program features.
      }

      刪除
    3. 你好,我不是學生,只是目前有一個案子廠商指定要用STM8S003,我沒用過ST MCU,先前都是用microchip,holtek,這個程式我只是測試一下interrupt的寫法,原本是主程式delayms(200)去延遲,後來改成用中斷方式,只是結果不是我所預期,它不是會自動載入嗎?應該會重新計數,怎麼感覺從中斷跳出去之後又跳進中斷,請問依照你上頭所說來改,就能讓PA1 Hi,Lo的時間嗎?

      刪除
    4. 喔~~PIC與8051指令集.
      ST MCU 硬體架構比較類似現在32bit MCU的架構.

      你要持續讓GPIO output Hi or Lo,可以在main()下觸發Time4中斷後,將GPIO控制的程式放在
      @far @interrupt void TIM4InterruptHandle (void)
      {
      //Add your program features.
      }

      ,我之前有用過偉詮電子的MCU,我發現各家的硬體設計多多少少都有些差異,除非都是跟同一家IP(創意電子 or 智原科技)公司買來的.

      刪除
    5. 你好,你的意思是若要持續計數的話(也就是固定時間產生中斷一次),就需再中斷副程式裡增加
      TIM4_SR=0;
      TIM4_CR1=0x00;
      TIM4_CR1=0x01;
      這樣使TIM4 disable再使其enable,TIM4_ARR的值才會再載入counter計數?我這樣說對嗎?

      刪除
    6. 請問一下,您現在是要讓GPIO_A的第二pin持續輸出一個很精準時脈的方波,是嗎?

      刪除
    7. 對,沒錯,雖然clock是由內部提供,但還是希望在成本考量下盡量精準。

      刪除
    8. TIM4->SR = 0; //Clear Flag
      就已經是將旗標清除,旗標清除後Time4的counter就會重新計數,

      我覺得你可以參考下列的寫法看看可不可以用:

      int main(void)
      {
      GPIOA_Init();
      TIM4_Init();

      enableInterrupts(); //InterruptInit

      while(1)
      {
      TIM4->CR1 = 0x01; //Counter enable
      GPIOA->ODR |= 0x08; //Hi

      TIM4->CR1 = 0x01; //Counter enable
      GPIOA->ODR &= ~(0x08); //Lo

      }

      return 0;
      }

      @far @interrupt void TIM4InterruptHandle (void)
      {
      TIM4->SR = 0; //Clear Flag
      }

      刪除
    9. 你好,我是過你的方法一樣不行,先前我用debug mode時發現它一進中斷副程式就會在中斷副程式裡RUN無法返回主程式,依你的經驗可告知是那出錯了嗎?以下是我的程式碼
      main.c
      /* MAIN.C file
      *
      * Copyright (c) 2002-2005 STMicroelectronics
      */
      #include "iostm8s.h"

      void delayms(unsigned int ms)
      {
      unsigned char i;
      while(ms != 0)
      {
      for(i=0;i<250;i++)
      {
      }
      for(i=0;i<75;i++)
      {
      }
      ms--;
      }
      }

      main()
      {
      CLK_SWR=0xe1;
      //CLK_CKDIVR=0x08;
      PA_DDR=0b00001110;
      PA_CR1=0b00001110;
      PA_CR2=0x00;
      PB_DDR=0b00100000;
      PB_CR1=0b00100000;
      PB_CR2=0x00;
      PC_DDR=0b00101000;
      PC_CR1=0b00101000;
      PC_CR2=0x00;
      PD_DDR=0b00000110;
      PD_CR1=0b00000110;
      PD_CR2=0x00;
      //TMR4 setting
      TIM4_IER=0x00;
      CLK_PCKENR1=0x10;
      TIM4_EGR=0x01;
      TIM4_PSCR=0x07;
      TIM4_ARR=0x80;//250;
      //TIM4_CNTR=250;
      TIM4_CR1=0x00;//0x01;
      TIM4_IER=0x01;
      //TMR4 setting
      _asm("rim"); //Enable interrupt (level 0 set)
      while (1)
      {
      //PA_ODR=PA_ODR | 0b00001110;
      //delayms(200);
      //PA_ODR=PA_ODR & 0b11110001;
      /*PB_ODR=PB_ODR | 0b00100000;
      delayms(200);
      PB_ODR=PB_ODR & 0b11011111;
      PC_ODR=PC_ODR | 0b00101000;
      delayms(200);
      PC_ODR=PC_ODR & 0b11010111;
      delayms(200);
      PD_ODR=PD_ODR | 0b00000110;
      delayms(200);
      PD_ODR=PD_ODR & 0b11111001;
      delayms(200);*/
      TIM4_CR1=0x01;
      PA_ODR=PA_ODR | 0b00000010;
      TIM4_CR1=0x01;
      PA_ODR=PA_ODR & 0b11111101;
      }
      }
      @far @interrupt void tmr4_interrupt(void)
      {
      TIM4_SR=0x00;
      //PA_ODR=PA_ODR ^ 0x02;
      //TIM4_CR1=0x00;
      //TIM4_CR1=0x01;
      //return;
      }

      stm8_interrupt_vector.c
      /* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
      * Copyright (c) 2007 STMicroelectronics
      */

      typedef void @far (*interrupt_handler_t)(void);

      struct interrupt_vector {
      unsigned char interrupt_instruction;
      interrupt_handler_t interrupt_handler;
      };

      @far @interrupt void NonHandledInterrupt (void)
      {
      /* in order to detect unexpected events during development,
      it is recommended to set a breakpoint on the following instruction
      */
      //PA_ODR=PA_ODR ^ 0x02;
      return;
      }

      extern void main();//_stext(); /* startup routine */
      extern @far @interrupt void tmr4_interrupt(void);
      //extern @interrupt void tmr4_interrupt(void);

      struct interrupt_vector const _vectab[] = {
      {0x82, (interrupt_handler_t)main},//_stext}, /* reset */
      {0x82, NonHandledInterrupt}, /* trap */
      {0x82, NonHandledInterrupt}, /* irq0 */
      {0x82, NonHandledInterrupt}, /* irq1 */
      {0x82, NonHandledInterrupt}, /* irq2 */
      {0x82, NonHandledInterrupt}, /* irq3 */
      {0x82, NonHandledInterrupt}, /* irq4 */
      {0x82, NonHandledInterrupt}, /* irq5 */
      {0x82, NonHandledInterrupt}, /* irq6 */
      {0x82, NonHandledInterrupt}, /* irq7 */
      {0x82, NonHandledInterrupt}, /* irq8 */
      {0x82, NonHandledInterrupt}, /* irq9 */
      {0x82, NonHandledInterrupt}, /* irq10 */
      {0x82, NonHandledInterrupt}, /* irq11 */
      {0x82, NonHandledInterrupt}, /* irq12 */
      {0x82, NonHandledInterrupt}, /* irq13 */
      {0x82, NonHandledInterrupt}, /* irq14 */
      {0x82, NonHandledInterrupt}, /* irq15 */
      {0x82, NonHandledInterrupt}, /* irq16 */
      {0x82, NonHandledInterrupt}, /* irq17 */
      {0x82, NonHandledInterrupt}, /* irq18 */
      {0x82, NonHandledInterrupt}, /* irq19 */
      {0x82, NonHandledInterrupt}, /* irq20 */
      {0x82, NonHandledInterrupt}, /* irq21 */
      {0x82, NonHandledInterrupt}, /* irq22 */
      {0x82, (interrupt_handler_t)tmr4_interrupt}, /* irq23 */
      {0x82, NonHandledInterrupt}, /* irq24 */
      {0x82, NonHandledInterrupt}, /* irq25 */
      {0x82, NonHandledInterrupt}, /* irq26 */
      {0x82, NonHandledInterrupt}, /* irq27 */
      {0x82, NonHandledInterrupt}, /* irq28 */
      {0x82, NonHandledInterrupt}, /* irq29 */
      };

      刪除
    10. 我的範例都是驗證過的因該沒有什麼問題,
      你可以列出你TIME4
      #define TIM4 ((TIM4_TypeDef *) TIM4_BaseAddress)

      /* @brief 8-bit system timer (TIM4) */

      typedef struct TIM4_struct
      {
      vu8 CR1; /*!< control register 1 */
      u8 RESERVED1; /*!< Reserved1 byte */
      u8 RESERVED2; /*!< Reserved2 byte */
      vu8 IER; /*!< interrupt enable register */
      vu8 SR; /*!< status register */
      vu8 EGR; /*!< event generation register */
      vu8 CNTR; /*!< counter register */
      vu8 PSCR; /*!< prescaler register */
      vu8 ARR; /*!< auto-reload register */
      }TIM4_TypeDef;
      這部分的程式碼嗎?
      STM8S不同的型號的IC TIME4的暫存器會有差異.

      刪除
    11. 你好,我沒用類似你用的結構方式,我是直接與暫存器溝通,你應該不是用COSMIC C complier吧

      刪除
    12. 1. 抱歉!請教一下,為什麼您會覺得我不是使用COSMIC C Compiler呢?
      2. 您可以列出Time4 暫存器的#define設定這部分的code嗎?

      刪除
    13. 1.你好,因為你的結構用法,我參考別人的範例都是我這種寫法,沒看過你這種寫法,因此懷疑你不是用COSMIC。
      2.下面所列是我include "iostm8s.h"裡的TIM4定義,提供給你做參考。
      /* TIMER 4 section
      */
      volatile char TIM4_CR1 @0x5340; /* Control register 1 */
      volatile char TIM4_IER @0x5341; /* Interrupt enable reg */
      volatile char TIM4_SR @0x5342; /* Status register */
      volatile char TIM4_EGR @0x5343; /* Event Generation reg */
      volatile char TIM4_CNTR @0x5344; /* Counter register */
      volatile char TIM4_PSCR @0x5345; /* Prescaler register */
      volatile char TIM4_ARR @0x5346; /* Auto-reload register */

      刪除
    14. 1. 我想結構的寫法是標準C/C++語言的語法,可能是您比較少用,不過ST的範例都是這樣寫的,我這部分是依照ST的範例做的.

      2. 你的MCU型號是STM8S003系列的嗎?
      如果是的話,你的設定就錯啦,請參考ST的文件DM00024550.pdf,第page 34,STM8S003的MCU Time4暫存器設定如下所示.

      TIME4_CR1 = 0x005340
      Reserved = 0x005341
      Reserved = 0x005342
      TIME4_IER = 0x005343
      TIME4_SR = 0x005344
      TIME4_EGR = 0x005345
      TIME4_CNTR = 0x005346
      TIME4_PSCR = 0x005347
      TIME4_ARR = 0x005348

      刪除
  3. 你好,感謝你的回覆,還好有你的幫忙,我查了一下確實如你所說,TIM4的暫存器位址確實定義錯了,我是找C:\Program Files (x86)\COSMIC\CXSTM8_32K\Hstm8底下的iostm8s.h,因為裡頭我找不到stm8s003.h檔,因此找一個叫相近的檔案也沒想那麼多,但問題來了,難道我要一個一個去修改暫存器的位址嗎?

    回覆刪除
  4. 你好,問題已經解決了,我看了資料stm8s003與stm8s103暫存器位址是一樣,所以我include stm8s103.h,非常感謝你這兩天的協助。

    回覆刪除
  5. 你好,請教一下,TIM4的中斷有兩個條件,一是overflow另一個是寫入TIME4_CNTR,我看了資料也試了很多方法,但就是無法寫入TIME4_CNTR時不產生中斷,請問有什麼方法可以解決這個問題嗎?TIM4中斷我只想overflow產生中斷,寫入TIME4_CNTR不產生中斷。

    回覆刪除
    回覆
    1. 1. 請教一下,您可以秀出您的TIME4初始化設定值嗎?
      2. 因為我之前使用他家的MCU Time時都習慣使用向下計數,假設初始值是0x8000向下計數至0x0000為1s就會產生一個flag中斷信號,清除flag後又會重新計數.

      刪除
    2. sorry,是我誤會了,原以為它是像下計數,後來用debug才知道實際上是up counter,TIM4_CNTR會跟TIM4_ARR做比較,實際上寫入TIM4_CNTR是不會產生中斷。

      刪除
    3. 從您之前的留言看來,您是設定成向上計數,
      你要改向下計數也是可以, TIME4_CR1的 URS初始值設1,就可以了.

      Bit 2 URS: Update request source
      0: When enabled, an update interrupt request is sent as soon as registers are updated (counter
      overflow).
      1: When enabled, an update interrupt request is sent only when the counter reaches the
      overflow/underflow.

      刪除
    4. 再次請教,我要將PB5設成digital input and pull up,程式設定如下
      PB_DDR=0b00000000;
      PB_CR1=0b00110000; //Input with pull-up
      PB_CR2=0x00; //PB External interrupt disabled
      但我量PB5 pin腳(PB5空接)並沒有量到+5V的電壓,量到的是0V,這是怎麼回事?

      刪除
    5. GPIO當做input時,是不可以float的,請將PB5接個Pull high電阻(4.7k歐姆)至VDD.

      刪除
    6. 可是我看stm8s003 datasheet,其Px_CR1若設為1則為pull-up,也就是內部提昇電阻啟動了,下面是Px_CR1的說明。
      In input mode (DDR = 0):
      0: Floating input
      1: Input with pull-up

      刪除
  6. 你好,已經找到問題點了,在stm8s003p3 datasheet P19有說明PB4,PB5為true open-drain I/O,所以無法設pull-up。

    回覆刪除
    回覆
    1. 下列的意見您可以參考看看:
      您可以看一下ST文件DM00024550.pdf page26~27,
      其中每的portP?_IDR Port ? input pin value register 0xXX(1),
      都會有" 0xXX(1)",
      他有個註解是這樣寫的" (1)Depends on the external circuitry."
      所以您再參考DM0004010.pdf, page17的電路圖,PB7的輸入也是這樣設計的,

      刪除
  7. 你好,請教一下,有關於EEPROM的寫入或讀取,有沒有比下面我寫的還要更好得方式,我寫的會造成短暫時間的無窮迴圈,這並不是一個好得方式,而且對EEPROM做讀寫動作時,中斷似乎會被暫停。
    do
    {
    FLASH_DUKR=0xae;
    FLASH_DUKR=0x56;
    }while(_DUL==0);
    eeprom_lig_on1=lig_on1_on_count;
    _DUL=0;

    回覆刪除
    回覆
    1. 您這顆的EEPROM的型號是?

      刪除
    2. STM8S的EEPROM 我是沒有用過啦,

      不過在你的說明下我大致了解您的問題,
      依照您的寫法,當_DUL==0之前,
      FLASH_DUKR=0xae;
      FLASH_DUKR=0x56;
      這兩行程式會被重複執行對嗎,您覺得這樣不好是嗎?

      如果是這樣,您就直接改成,

      FLASH_DUKR=0xae; //只會執行一次.
      FLASH_DUKR=0x56; //只會執行一次.
      while(_DUL==0); //當_DUL為0時,才會執行下一行指令.
      eeprom_lig_on1=lig_on1_on_count;

      刪除
    3. 感謝你的回覆,我已經詢問過ST FAE,寫入EEPROM時需6ms的時間,且寫入期間不允許任何的中斷,也就是這6ms程式等於在當機狀態

      刪除
  8. 你好,請教PWM問題,我使用TIM1 channel 3輸出PWM訊號,以下是原始檔,但在輸出端pin13 PORT c3(stm8s003)量不到pwm訊號,請教是哪兒出了問題?感謝你
    /* MAIN.C file
    *
    * Copyright (c) 2002-2005 STMicroelectronics
    */
    #include "iostm8s103.h"

    _Bool PA1 @PA_ODR:1;
    _Bool PD2 @PD_ODR:2;

    void delayms(unsigned int ms)
    {
    unsigned char i;
    while(ms != 0)
    {
    for(i=0;i<250;i++)
    {
    }
    for(i=0;i<75;i++)
    {
    }
    ms--;
    }
    }

    main()
    {
    CLK_SWR=0xe1; //fhsi=16MHz
    CLK_CKDIVR=0x10; //fhsi/4=4MHz
    PA_DDR=0b00001110;
    PA_CR1=0b00001110;
    PA_CR2=0x00;
    PB_DDR=0b00100000;
    PB_CR1=0b00100000;
    PB_CR2=0x00;
    PC_DDR=0b00101000;
    PC_CR1=0b00101000;
    PC_CR2=0x00;
    PD_DDR=0b00001110;
    PD_CR1=0b00001110;
    PD_CR2=0x00;
    //TMR4 setting
    TIM4_IER=0x00;
    CLK_PCKENR1=0x10;
    TIM4_EGR=0x01;
    TIM4_PSCR=0x07; //Fosc/128=4MHz/128=31.25KHz
    TIM4_ARR=2; //31.25k/10k=3.125
    //TIM4_CNTR=250;
    TIM4_CR1=0x01;
    TIM4_IER=0x01;
    //TMR4 setting
    //TIM2 setting
    TIM2_CCMR2=0x78;//TIM2_CCMR2 | 0x70;
    TIM2_CCER1=TIM2_CCER1 | 0x30;
    TIM2_ARRH=0;
    TIM2_ARRL=0xff;
    TIM2_CCR2H=0;
    TIM2_CCR2L=0;
    TIM2_PSCR=0;
    TIM2_CR1=TIM2_CR1 | 0x01;
    //TIM2 setting
    //TIM1 setting
    TIM1_CR1 =TIM1_CR1 & 0xfe;
    TIM1_PSCRH=0;
    TIM1_PSCRL=0;
    TIM1_ARRH=0;
    TIM1_ARRL=49;
    TIM1_CR1=TIM1_CR1 | 0x80;
    TIM1_EGR=TIM1_EGR | 0x01;
    TIM1_CCR3H=0;
    TIM1_CCR3L=25;
    TIM1_CCMR3=104;
    TIM1_CCER2=TIM1_CCER2 | 0x01;
    TIM1_CR1=TIM1_CR1 | 0x01;
    TIM1_BKR=TIM1_BKR | 0x80;
    //TIM1 setting
    _asm("rim"); //Enable interrupt (level 0 set)
    TIM2_CCR2H=0;
    TIM2_CCR2L=12;
    while (1)
    {
    //PA_ODR=PA_ODR | 0b00001110;
    //delayms(200);
    //PA_ODR=PA_ODR & 0b11110001;
    /*PB_ODR=PB_ODR & 0b11011111;
    PB_ODR=PB_ODR | 0b00100000;
    //delayms(200);
    PB_ODR=PB_ODR & 0b11011111;
    PC_ODR=PC_ODR | 0b00101000;
    //delayms(200);
    PC_ODR=PC_ODR & 0b11010111;
    //delayms(200);
    PD_ODR=PD_ODR & 0b11111001;
    PD_ODR=PD_ODR | 0b00000110;
    //delayms(200);
    PD_ODR=PD_ODR & 0b11111001;*/
    //delayms(200);
    //TIM4_CR1=0x01;
    //PA_ODR=PA_ODR | 0b00000010;
    //TIM4_CR1=0x01;
    //PA_ODR=PA_ODR & 0b11111101;
    }
    }
    @far @interrupt void tmr4_interrupt(void)
    {
    TIM4_SR=0x00;
    //PA_ODR=PA_ODR ^ 0x02;
    //TIM4_CR1=0x00;
    //TIM4_CR1=0x01;
    //return;
    //PA_ODR=0x00;
    //PA_ODR=0x02;
    //PA_ODR=0x00;
    //PA1=!PA1;
    PD2=!PD2;
    }

    回覆刪除