Hier sollen daher nur Programmierbeispiele für die STM32-Serie stehen die auch funktionieren UND getestet wurden.

  • Digital IO
  • Serial IO
  • Analog IO
  • CAN Bus IO

Zur Programmierumgebung IDEs und deren Einrichtung gibts genügend Infos im Web, daher verzichte ich hier mal darauf.

Hier ist eine erste Anlaufstelle.

und hier ist noch eine: Setting up Eclipse and Code Sourcery lite for STM32 Discovery Development

Die Beispiele beziehen sich auf das obige Demo Board von Olimex STM32P107. Aufgrund der gleichen Architektur der Cortex-Serie können die Beispiele auch leicht für andere CPUs aus der gleichen Serie sogar von anderen Herstellern verwendet werden ohne dass man groß Änderungen vornehmen muss. Dies ist in meinen Augen der größte Vorteil gegenüber den AVRs von ATMEL, wo man bei einem CPU Wechsel jedesmal alle Register etc. neu anpassen muss - soweit zumindest die Theorie. Die gelisteten Programme sind so aufgebaut, dass quasi alle Quellen in einem File enthalten sind damit dies im Webbrowser besser zu lesen ist. Ich empfehle jedoch die Aufteilung der Quellen in Header- und Libraryfiles, sodass man die Routinen leicht wiederverwenden kann und man auch eine bessere Übersichtlichkeit bekommt.

Voraussetzungen:

  • Windows PC mit Betriebssystem Windows 7,
  • Programmierumgebung: Eclipse basierte IDE (CooCox CoIDE) in der Version: 1.6.2
  • Programmieradapter: ST-LINK/V2
  • Olimex-Boards STM32-P107 und Olimexino STM31

Digital IO

Einfaches Testprogramm - das Hello World der Elektroniker - um 2 LEDS blinken zu lassen. Zwar einfach aber als Test um die Toolchain und Programmierhardware etc. zu testen völlig ausreichend.

/* Wolfram Koerver
 * STM32 Example for OLIMEX STM32P107 Test Board
 * Toggle green and yellow LEDs Test Program this is the "hello world for electronics"
 * 1.1.2013
 */
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void init_GPIO(void);
void delay_nus(uint32_t nus);
int main(void)
{
	init_GPIO();
    while(1)
    {
		/* Toggle LEDs which connected to PC6 and PC7 ; Green/Yellow LEDs from Olimex Board*/
		GPIOC->ODR ^= GPIO_Pin_6;						// invert pin
		delay_nus (100000);								// delay a short time
		GPIOC->ODR ^= GPIO_Pin_7;						// toggle other LED
		delay_nus (100000);
    }
}
void init_GPIO(void)
{
    /* Initialize GPIO Structure, configure clock on peripheral bus
     * Enable GPIO Pins for LED which are connected to PC6,7*/
    /* Configure the GPIO_LED pin  PC6 = Green LED PC7 = Yellow LED
     * Configure direction and clock speed*/
	GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/***************************************************************************//**
 * @brief     delay in n us
 * @param[in] n:delay value
 * @return    None
*******************************************************************************/
void delay_nus(uint32_t nus)
{
 uint32_t temp;
 SysTick->LOAD = nus * 11;
 SysTick->VAL = 0x00;
 SysTick->CTRL = 0x01 ;
 do
 {
  temp=SysTick->CTRL;
 }while(temp&0x01&&!(temp&(1<<16)));
 SysTick->CTRL = 0x00;
 SysTick->VAL = 0X00;
}

 

Nachfolgend noch der Download link für das Demoprogramm.

Wie man die einzelnen Bits oder Ports anspricht findet sich hier.

SERIAL IO

Wie spricht man die USART Schnittstellen des STM32 an ?

Für die Cortex CPU Serie hat ST viele Funktionen auf einem Chip integriert mit dem Problem: Wie verwendet man was und wann ? Da ist eine Schnittstelle in die CPU hinein recht hilfreich.

Spätestens wenn man die ersten Schritte in der Programmierung mit der neuen CPU macht, muss man mitunter auch Debug-Infos etc. ausgeben können. Dies ist im einfachsten Fall per ST LINK und Debugger leicht möglich, aber manchmal will man auch einfach aktuelle Werte von Variablen oder ADC-Werte zum Test kontinuierlich ausgeben können. In diesem Fall muss man zunächst eine serielle Schnittstelle einrichten die die Ausgabe übernimmt. Diese Schnittstelle kann man dann mit einem Terminalprogramm vom PC aus bedienen.

Nachfolgend ist ein einfaches Testprogramm um die USART Schnittstellen 1 und 2 anzusprechen.

#include <stdio.h>
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include <stddef.h>
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
	
// Function prototypes
void InitUart1(void);
void InitUart2(void);
void RCC_Init(void);
void USART1_SendString(char* data);
void USART2_SendString(char* data);
void delay_nus(uint32_t nus);
/***************************************************************************//**
 * @brief     delay some time ;n us
 * @param[in] n:delay value
 * @return    None
*******************************************************************************/
void delay_nus(uint32_t nus)
{
 uint32_t temp;
 SysTick->LOAD = nus * 11;
 SysTick->VAL = 0x00;
 SysTick->CTRL = 0x01 ;
 do
 {
  temp=SysTick->CTRL;
 }while(temp&0x01&&!(temp&(1<<16)));
 SysTick->CTRL = 0x00;
 SysTick->VAL = 0X00;
}
void RCC_Init(void)
{
	// Route and enable clocks for low and high speed bus
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
}
void InitUart1(void)
{
	// Create Structs
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	USART_ClockInitTypeDef USART_ClockInitStructure;
	// USART1 RX-Pin initialize
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	// USART1 TX-Pin initialize
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	// USART and clock initialize
	USART_ClockStructInit(&USART_ClockInitStructure);
	USART_ClockInit(USART1, &USART_ClockInitStructure);
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART1, &USART_InitStructure);
	USART_Cmd(USART1, ENABLE);
}
void InitUart2(void)
{
	// Initialize Structs
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	USART_ClockInitTypeDef USART_ClockInitStructure;
	// USART1 RX-Pin initialize PD6
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	// USART1 TX-Pin initialize PD5
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	/* Remap USART, as USART2 is used as alternate pins on PD5/6*/
	GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
	// USART initialize
	USART_ClockStructInit(&USART_ClockInitStructure);
	USART_ClockInit(USART2, &USART_ClockInitStructure);
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART2, &USART_InitStructure);
	USART_Cmd(USART2, ENABLE);
}
void USART1_SendString(char* data)
{
	while (*data)
	{
		USART_SendData(USART1, (uint16_t) *data);
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
		data++;
	}
}
void USART2_SendString(char* data)
{
	while (*data)
	{
		USART_SendData(USART2, (uint16_t) *data);
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC)==RESET);
		data++;
	}
}
// *******************************************************************
// ***************************** Main ********************************
// Wolfram 2012 - Test program for USART IO
// *******************************************************************
// ***************************** Main ********************************
int main(void)
{
	SystemInit();
	RCC_Init();
	InitUart1();
	InitUart2();
	while(1)
	{
		delay_nus(100000);
		USART1_SendString("First String\n");
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
		delay_nus(100000);
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
		USART2_SendString("Second String\n\r");
	}
}

Im obigen Beispiel wird der USART1 und USART2 angesprochen.

Achtung, nicht einfach die USART Nummern umbenennen wenn ein anderer USART verwendet werden soll - das geht ohne Studium der Chip-Doku schief, da viele Register miteinander in logischer Verbindung stehen.

Auch ist es ratsam bei der Programmierung die Interruptprogrammierung in EINER Routine unterzubringen, statt je Interruptquelle in separaten Routinen. Sonst programmiern sich diese gegenseitig die Register um und man wundert sich warum ein Interrupt partout nicht kommt.

Die Pinbelegung ist :

USART1 : PA9 (Tx) und PA10(Rx) auf Port A

USART2 : PA5 (Tx) und PA6 (Rx) auf Port D

Achtung diese Anschlüsse sind die direkten CPU-Anschlüsse, die müssen über passende TTL/RS232 Wandler angeschlossen werden.

Auf dem Olimex Board STM32-P107 ist der UART2 direkt über einen Wandler auf eine 9-polige Buchse herausgeführt. Da ist natürlich kein Wandler mehr erforderlich.

Hier ist das Programm als Downloadlink:

Timer & Interrupts

Im richtigen "Leben" eines Microcontrollerprogramms benötigt man eigentlich immer genaue Zeiten. Damit ein Prozessor auch zwischendurch quasi andere Dinge erledigen kann (und auch muss) sind Interrupts am besten geeignet. Nachfolgend ist ein Programm welches den Timer TIM2 so programmiert, dass alle 1ms ein Interrupt ausgelöst wird.

#include <stdio.h>
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include <stddef.h>
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include <string.h>
#include <misc.h>
/*
 * Program to test the TIM2 timer and interrupt function for STM32F107VC.
 * tested with OLIMEX STM32-P107 board.
 * Wolfram Koerver - 5.1.2012
 * Program starts blinking with approx 1/sec with the yellow LED on port PC7
 * Interrupt is generated every 500us to flip the green LED on/off on port PC6
 */
void init_LED(void);
void blink_yellow(void);
void blink_green(void);
void toggle_green(void);
void init_timer(void);
void init_DO(void);
void toggle_do(void);
void toggle_dot(void);
void delay_us(uint32_t time_us);
void delay_ms(uint32_t time_ms);
void TIM2_IRQHandler(void);
void init_sys_tick(void);
int main(void)
{
	SystemInit();					// initialize the core
	init_LED();						// Init the LED port IOs
	init_DO();						// init digital output ports for digital signal
	init_timer();					// configure the Timer Interrupt
    while(1)
    {
    	toggle_green();
    	//blink_yellow();				// let the main program do something
    	delay_ms(500);
    }
}
void TIM2_IRQHandler(void){			// Timer Interrupt handler for TIM2 will be called every 1ms
  TIM_ClearITPendingBit(TIM2, TIM_IT_Update);	// Clear interrupt pending bit
  //toggle_green();					// just toggle the output port bit
  toggle_dot();						//generate output bit pulse on output
}
void init_timer(void)
{
	// SystemCoreClock = 72MHz -> APB1 is maximum 36MHz for TIM2,3,4,5 but will be doubled again to 72MHz when prescaler # 0
	// This example uses TIM2 Timer
	// APB1 clock = SystemCoreClock/2 but s.o.
	TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBase_InitStructure.TIM_Period 			= 999;		// count up to 999 = 1000
	TIM_TimeBase_InitStructure.TIM_Prescaler		= 71;		//72(MHz) -1 Divided by 72
	TIM_TimeBase_InitStructure.TIM_CounterMode 		= TIM_CounterMode_Up;
	//
	// 1MHz / 500 = 2000 Hz.
	// SystemCoreClock = 72MHz / 72 => 1 MHz Clock with this clock the timer counts up to 999 = 1000 counts =
	// 1/1000 --> 1000 Hz = 1ms cycle time
	TIM_TimeBaseInit(TIM2, &TIM_TimeBase_InitStructure);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
	NVIC_Init(&NVIC_InitStructure);
	TIM_Cmd(TIM2, ENABLE);
}
void delay_us(uint32_t nus)
{
 uint32_t temp;
 SysTick->LOAD 	= nus * 11;
 SysTick->VAL 	= 0x00;
 SysTick->CTRL 	= 0x01 ;
 do
 {
  temp=SysTick->CTRL;
 }while(temp&0x01&&!(temp&(1<<16)));
 SysTick->CTRL = 0x00;
 SysTick->VAL = 0X00;
}
void delay_ms(uint32_t time_ms) //Delay in msec
{
  while (time_ms>0)
  {
	delay_us(1000);
    time_ms--;
  }
}
void init_DO(void)
{
	/*
	 * the following statements are for the DO Output Pins to measure
	 * Clock settings. Initialize GPIO Structure, configure clock on peripheral bus
	 * Enable GPIO Pins PD8
	 * Configure direction and clock speed
	 */
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void init_LED(void)
{
		// the following statements are for the LEDs
	/* Initialize GPIO Structure, configure clock on peripheral bus
	 * Enable GPIO Pins for LED which are connected to PC6,7*/
	/* Configure the GPIO_LED pin  PC6 = Green LED PC7 = Yellow LED
	 * Configure direction and clock speed*/
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void blink_yellow()
{
	GPIOC->BRR = GPIO_Pin_7;						//reset bit
	GPIOC->BSRR = GPIO_Pin_7;						//set bit
	//delay_nus(30000);
	delay_ms(1);
	GPIOC->BRR = GPIO_Pin_7;						//reset bit
	//GPIOC->ODR ^= GPIO_Pin_7;						// invert pin
}
void blink_green()
{
	GPIOC->BRR = GPIO_Pin_6;						//reset bit
	GPIOC->BSRR = GPIO_Pin_6;						//set bit
	delay_ms(1);
	GPIOC->BRR = GPIO_Pin_6;						//reset bit
	//GPIOC->ODR ^= GPIO_Pin_6;						// invert pin
}
void toggle_green()
{
	GPIOC->ODR ^= GPIO_Pin_6;						// invert pin
}
void toggle_yellow()
{
	GPIOC->ODR ^= GPIO_Pin_7;						// invert pin
}
void toggle_do()
{
	GPIOD->ODR ^= GPIO_Pin_8;						// invert pin
}
void toggle_dot()
{
	GPIOD->BSRR = GPIO_Pin_8;						//set bit
	delay_us(1);
	GPIOD->BRR = GPIO_Pin_8;						//reset bit
}

Hierzu wird dann in der Interruptroutine ein Hardwareausgang getoggelt. Im Interrupt-handler void TIM2_IRQHandler(void) kann man dann z.B. zeitbezogene Aktionen ausführen. Hier sollten dann natürlich nur kurze Funktionen eingebaut werden, wie z.B. einlesen von digitalen Werten der IO Ports oder zum Beispiel Entprellfunktionen etc.. In der Hauptschleife des Programms wird eine LED zum Blinken gebracht. Eine delay Funktion auf Basis des SysTicks sorgt für ein Blinken im Sekundentakt; hierzu muss daher kein extra Timer verschwendet werden.

Hier ist das Programm als Downloadlink:

CAN Communication mit STM32

Um mit dem CAN Bus zu kommunizieren benötigt man natürlich die Angabe der Bitrate. Wenn die einmal bekannt ist, muss man den STM32 eben nur noch auf die passende Rate einstellen. Hierzu dienen diverse Register. Um die Registereinstelllungen nicht jedesmal neu zu berechnen folgt hier eine Tabelle mit den Einstellungen: (Angaben sind für das Olimexino Board und dem Prozessor STM32F103RB bei eine APB1 Takt von 36MHz).

APB1=36MHz      

Baudrate

kBit/s

CAN_Prescaler

CAN_BS1_

Register

CAN_BS2_

Register

2000

1 12 5
1000 2 12 5
500 4 12 5
400 5 12 5
250 8 12 5
200 10 12 5
125 16 12 5
100 20 12 5
50 40 12 5
25 80 12 5
10 200 12 5

Oder direkt als C code:

...
CAN_StructInit(&CAN_InitStructure);
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
//CAN_InitStructure.CAN_Prescaler=1;        // 2000kbit/s
//CAN_InitStructure.CAN_Prescaler=2;        // 1000kbit/s
CAN_InitStructure.CAN_Prescaler=4;        //  500kbit/s
//CAN_InitStructure.CAN_Prescaler=5;        //  400kbit/s
//CAN_InitStructure.CAN_Prescaler=8;        //  250kbit/s
//CAN_InitStructure.CAN_Prescaler=10;       //  200kbit/s
//CAN_InitStructure.CAN_Prescaler=16;       //  125kbit/s
//CAN_InitStructure.CAN_Prescaler=20;       //  100kbit/s
//CAN_InitStructure.CAN_Prescaler=40;       //   50kbit/s
//CAN_InitStructure.CAN_Prescaler=80;       //   40kbit/s
//CAN_InitStructure.CAN_Prescaler=200;      //   10kbit/s

Beispielprogramm zu vollständigen CAN-Kommunikation findet sich in diesem Beitrag.

TSIC Temperaturerfassung

Hier folgt jetzt ein kleines STM32 Testprogram welches einen TSIC-Temperatursensor ausliest. Zusätzlich wird noch ein Taster auf dem Demoboard abgefragt und eine LED zum blinken gebracht. Das Beispiel wurde für das STM-32-P107 Demoboard geschrieben. Die Kernroutine zum lesen der Temperatur ist: readTSicTemp. Über die serielle Schnittstelle wird der aktuelle Temperaturwert dann ausgegeben.

Achtung nicht vergessen:

Damit sprintf Funktionen für die UART-Ausgaberoutinen einwandfrei funktionieren muss man folgendes beachten:

1. Erhöhung der stack size

Dies erfolgt im File startup_stm32f10x_cl.c dort sind nur 200 bytes also 100 Worte vorgesehen.

#define STACK_SIZE 0x00000100 /*!< Stack size (in Worten) */

ersetzen durch

#define STACK_SIZE 0x00002000

(das gibt dann wenigstens 4kB) sowie im File:

(void *)&pulStack[STACK_SIZE-1], ersetzen durch

(void (*)(void))((unsigned long)pulStack + sizeof(pulStack)),

ersetzen. Sofern größere Texte zu verarbeiten sind sollte man die Größe noch weiter erhöhen. Es gibt ja genug ;-)

Wie spricht man denn jetzt TSIC Sensoren an ? Nun - eigentlich muss man nichts tun außer auf die erste fallende Flanke der Datenleitung zu warten, dann im Abstand der Taktrate die Bits einzeln einlesen. Eigentlich recht einfach. Nachteil ist, man weiß nicht WANN denn der Sensor die Daten sendet. Die Daten werden alle 100ms ausgesendet, d.h. man muss bis zu 100ms warten bevor man wieder den Beginn des Telegramms erkennen kann. Daher hat die Routine auch einen Timeoutparameter den man dann am besten auf 150ms setzt. falls kein Sensor angeschlossen ist, wird ein Fehler zurückgegeben - nach der Timeoutzeit. Der Sensor wird quasi nur mit 5V versorgt und die Datenausgangsleitung an GPIOD - PIN1 angeschlossen. Hier gibts übrigens Informationen zum verwendeten Sensor von ist-ag. Die Routinen wären sicherlich einfacher gewesen, wenn man diese über Interruptfunktionen implementiert hätte. Ich wollte aber für eine solche Sekundärfunktion keinen Interruptpin verschwenden, zumal sich Temperaturen ohnehin nur langsam ändern.

/* ***********************************************************************************************
 *
 * This program is a test program to read a TSIC temperature sensor TSIC 306 connected to the OLIMEX STM32-P107 Board.
 * Connected to GPIOD - PIN1; Button is read and green LED does blink
 * Wolfram Koerver, 2012
 *
 * ***********************************************************************************************/
#include <stdio.h>
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include <stddef.h>
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include <string.h>
#include <misc.h>
#include <stdlib.h>
/* function prototypes */
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART1_IRQHandler(void);
void USART1_SendString(char* data);
void USART2_SendString(char* data);
void delay_nus(uint32_t nus);
void Init_Led(void);
void blink_yellow(void);
void blink_green(void);
void InitUart2(void);
void USART2_SendString(char* data);
void USART_puts(USART_TypeDef* USARTx, volatile char *s);
void Init_TSICPort(void);
unsigned int read_sw(void);
void RCC_Init(void);
uint8_t readTSicTemp (uint16_t *temp_value16, uint8_t channel, uint32_t timeout);
//Interrupt handler declaration
void USART2_IRQHandler();
char bufferRx[127],receiveRx[127];
int RxCounter,printRx,switch_port;
int main(void)
{
	uint16_t 		temperatur;
	uint8_t 		returnvalue;  // return value of getTSicTemp(*temp);
	float 			grad;
	char			out_text[50];
	SystemInit();
	RCC_Init();
	NVIC_Configuration();
	Init_Led();
	InitUart2();
	Init_TSICPort();
	USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
	/* Enabling interrupt from USART2 */
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	USART2_SendString("Program Start\n\r");
	//while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
	while(1)
	{
		delay_nus(500000);		// wait 0.5s
		blink_yellow();			// blink yellow LED every 500ms
		returnvalue = readTSicTemp(&temperatur,1,50000);  // fetch TSIC temp
		out_text[49] = '\0';	// make sure string termination
		if (returnvalue == 0){
			// conversion to temperature
			grad = ((float)temperatur / 2047 * 200) - 50;
			out_text[49] = '\0';
			sprintf(out_text,"TSIC %4.5f",grad);
			USART_puts(USART2,out_text);
			while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
			USART_puts(USART2,"deg C  ");
			while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
			sprintf(out_text,"TSICRAW %6d  \r",temperatur);
			USART_puts(USART2,out_text);
			while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
		} else {
			sprintf(out_text,"Return Error %2d",returnvalue);
			USART_puts(USART2,out_text);
			while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
			USART_puts(USART2," \r ");
			while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
		}
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
		      blink_green();
	}
}
void delay_nus(uint32_t nus)
{
 uint32_t temp;
 SysTick->LOAD = nus * 11;
 SysTick->VAL = 0x00;
 SysTick->CTRL = 0x01 ;
 do
 {
  temp=SysTick->CTRL;
 }while(temp&0x01&&!(temp&(1<<16)));
 SysTick->CTRL = 0x00;
 SysTick->VAL = 0X00;
}
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	/* Configuring USART1_Tx as 'alternate function push-pull' */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	/* Configuring USART1_Rx as 'input floating' */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Init_Led(void)
{
	// the following statements are for the LEDs
	/* Initialize GPIO Structure, configure clock on peripheral bus
	 * Enable GPIO Pins for LED which are connected to PC6,7*/
	/* Configure the GPIO_LED pin  PC6 = Green LED PC7 = Yellow LED
	 * Configure direction and clock speed*/
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void Init_TSICPort(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	// Pin Floating
	//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	//Pin Up
	//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	//Pin Down
	GPIO_Init(GPIOD, &GPIO_InitStructure);
}
unsigned int read_sw(void){
	int dataHalfWord;
	dataHalfWord = GPIO_ReadInputData(GPIOC);
	return dataHalfWord;
}
void blink_yellow()
{
	GPIOC->BSRR = GPIO_Pin_7;						//set bit
	delay_nus(10000);
	GPIOC->BRR = GPIO_Pin_7;						//reset bit
	//GPIOC->ODR ^= GPIO_Pin_7;						// invert pin
}
void blink_green()
{
	GPIOC->BSRR = GPIO_Pin_6;						//set bit
	delay_nus(10000);
	GPIOC->BRR = GPIO_Pin_6;						//reset bit
	//GPIOC->ODR ^= GPIO_Pin_6;						// invert pin
}
void toggle_green()
{
	GPIOC->ODR ^= GPIO_Pin_6;						// invert pin
}
void USART_puts(USART_TypeDef* USARTx, volatile char *s){
	while(*s){
		// wait until data register is empty
		while( !(USARTx->SR & 0x00000040) );
		USART_SendData(USARTx, *s);
		*s++;
	}
}
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the USART1 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    /* Enable the USART2 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //=0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
void USART2_IRQHandler(void)
{
	 //on overrun clear the OVR condition
	if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
	{
	  (void)USART_ReceiveData(USART2);
	}
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  {
     //Read byte from receive data register
    bufferRx[RxCounter++] = USART_ReceiveData(USART2);
   USART_SendData(USART2, bufferRx[RxCounter-1]);//echo
    if(bufferRx[RxCounter-1]=='\r'){
       strcpy(receiveRx, bufferRx);
       receiveRx[RxCounter-1]='\0';
       RxCounter=0;printRx=1;
      }
    if(RxCounter > 125)
    {
       //Disable the USART1 Receive interrupt
      USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
    }
  }
  toggle_green();
 }
void USART1_SendString(char* data)
{
	while (*data)
	{
		USART_SendData(USART1, (uint16_t) *data);
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
		data++;
	}
}
void USART2_SendString(char* data)
{
	while (*data)
	{
		USART_SendData(USART2, (uint16_t) *data);
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC)==RESET);
		data++;
	}
}
void InitUart2(void)
{
	// Initialize Structs
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	USART_ClockInitTypeDef USART_ClockInitStructure;
	// USART1 RX-Pin initialize PD6
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	// USART1 TX-Pin initialize PD5
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	/* Remap USART, as USART2 is used as alternate pins on PD5/6*/
	GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
	// USART initialize
	USART_ClockStructInit(&USART_ClockInitStructure);
	USART_ClockInit(USART2, &USART_ClockInitStructure);
	USART_InitStructure.USART_BaudRate = 19200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART2, &USART_InitStructure);
	USART_ITConfig (USART2, USART_IT_RXNE, ENABLE);
	USART_Cmd(USART2, ENABLE);
}
void RCC_Init(void)
{
	// Route and enable clocks for low and high speed bus
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
}
/******************************************************************************
* Description :   	Reads serial bits from TSIC sensor TSIC 206/208 etc.
* Parameters  :   	*temp_value16 : pointer for return raw temp value
* 					channel port IO bit to read from
* 					timeout : timeout in us
* Function Returns     :  0 = OK or Error, 1 = Timeout, 2 = Parity Error in Byte 1 or Byte 2
******************************************************************************/
uint8_t readTSicTemp (uint16_t *temp_value16, uint8_t channel, uint32_t timeout) {
  uint16_t temp_value1 = 0;
  uint16_t temp_value2 = 0;
  uint8_t i;
  uint16_t Temperature;
  uint8_t parity;
  uint32_t tim,tstrobe;
#define tsic_in GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_1)
  // wait until falling bit for first strobe pulse high->low
  // every 100ms a new telegram must arrive, so do not wait longer that 100ms = 100000us
  // then measure the exact strobe time
  tim = 0;
  while ((tsic_in) && (tim < 100000) ){
	  delay_nus(1);
	  tim++;
  }
  if (tim >=timeout) {
	  return 1;
  }
  // now we have detected somehow the falling edge. as long as this edge is low we just wait
  // until it gets high again: this is the strobe and start bit. Typically strobe bit last 60us.
  // wait until change from low->high then we can start reading bits and so on
  tim=0;
  while (!(tsic_in) && (tim < timeout) ){
 	  delay_nus(1);
 	  tim++;							// measure strobe time which varies with temp and is approx. 60us
   }
  if (tim >=timeout) {
	  return 1;
  }
  tstrobe = 2*tim;
  //*******************************************************************************
  // read first batch of : 8 data bits and 1 parity bit
  for (i = 0; i < 9; i++) {
    while  (tsic_in);              		// wait for high->low
	delay_nus(tstrobe);
    if (tsic_in)
    	{
        temp_value1 |= 1 << (8-i);
    	}
    else
        while (!( tsic_in ));           // wait for low-> high
  }
  //*******************************************************************************
  tim=0;
  while ((tsic_in) && (tim < 120) ){
  	  tim++;
  	  delay_nus(1);
  }
  // read second batch of : 8 data bits and parity bit
  tim=0;
  while (!(tsic_in) && (tim < timeout) ){
 	  tim++;							// measure strobe time which varies with temp and is approx. 60us
 	  delay_nus(1);
  }
  //*******************************************************************************
  for (i = 0; i < 9; i++) {
    while (tsic_in);               		// wait for high->low
	delay_nus(2*tim);					// strobe time * 2 is the bit time
    if (tsic_in){
        temp_value2 |= 1 << (8-i);      // get bit by bit
	}
      else
        while (!( tsic_in ));           // wait for low->high
  }
  //*******************************************************************************
  // parity check 1st byte
  parity = 0;
  for (i = 0; i < 9; i++)
    if (temp_value1 & (1 << i))
        parity++;
  if (parity % 2)
  return 2;
  // parity check 2nd byte
  parity = 0;
  for (i = 0; i < 9; i++)
    if (temp_value2 & (1 << i))
        parity++;
  if (parity % 2)
        return 2;					// parity NIO
  temp_value1 >>= 1;
  temp_value2 >>= 1;
  Temperature = (temp_value1 << 8) | temp_value2;
  *temp_value16 = Temperature;
  return 0;                       // parity ok  value ok so return 0
}

Hier ist das Programm zum Download: