- Werbung -

Nachdem wir im ersten Teil die Hardware ausreichend betrachtet und verdrahtet haben, kommen wir nun zur Software, zum eigentlichen Programm.
Programmiert wird der STM32 mittels C-Compiler und eigener Umgebung. Empfohlen vom Hersteller werden verschiedene Produkte, hier ein paar Beispiele:

  • Atollic - Truestudio
  • Keil - MDK Development Suite
  • Raisonance - Ride7
  • IAR - Workbench
  • GNU - C-Compiler (ja, eine Variante wird frei vertrieben)
  • Powley Crossworks
  • CodeRed
  • Yagarto - Eclipse-Umgebung und C-Compiler zum Integrieren
  • xduino - hört sich vielversprechend an, habe es aber noch nicht ausprobiert.
  • CooCox - CoIDE
  • Auch hier was → https://github.com/jsnyder/arm-eabi-toolchain

Die meisten bieten eingeschränkten Support an für freie (lite) Entwicklung, bzw. beschränken die maximale Codegröße. Beim Letzteren muss man ein wenig zusammen schustern bis es läuft, hält sich aber in Grenzen.. und es ist frei erhältlich.

Man gehe auf die Seite http://www.coocox.org, hole sich da das CoIDE als Editor bzw. Entwicklungsumgebung, CoFlash befindet sich gleich mit dabei, damit man das Programm aufs Board übertragen kann, und dann noch den C-Compiler, den man z.b. hier (Direkt-Download) findet oder hier von Launchpad.

Neues Projekt anlegen → Man wählt den entsprechenden Prozessorhersteller aus. Bei dem ST32VL – Discovery ist der Hersteller ST.

Jetzt den entsprechenden Prozessor-Typ, im Fall des STM32VL Discovery ist es der STM32F100RB.

Dann wählt man die Baugruppen aus, mit denen man programmieren will, in unserem Fall ist das GPIO (General Purpose Input Output, Allgemeine Ein- und Ausgänge). Was dazu noch benötigt wird, wählt das Programm dann automatisch mit dazu.

Jetzt fragt es ob ein Projekt erstellt werden soll, wir wählen Ja aus. Es hat Vorteile, alles in einem Projekt zu speichern, da sich so die Zusammengehörigkeit der Files besser definieren lässt.

Die Frage nach dem Projektnamen kann man sich selber überlegen, in unserem Fall nehmen wir auge-versuch

Hier kann jeder deutlich sehen, dass er automatisch das RCC und das CMSIS dazu gewählt hat. (Wir hatten nur auf das GPIO geklickt)

Als nächstes müssen wir den C-Compiler hinzufügen, bzw. den Pfad zur  Toolchain. Dazu gehen wir auf Projekt → Select Toolchain Path.

Wir verweisen auf den vorher installierten Arm GCC Compiler, deshalb wählen wir Browse

Und gehen auf C:\Program Files (x86)\arm-none-eabi-gcc-4_6\bin und sagen dann OK.

So wird dann der Pfad übernommen. 

Nachdem wir mit OK bestätigt haben, kommen wir wieder zurück zur Auswahl. Hier gehen wir auf unser Hauptprogramm (main.c). Hier sehen wir nun unser Hauptprogramm (main) und unsere Endlosschleife (while). Man könnte Ähnlichkeiten ziehen zum Arduino, wo man auch in 2 Funktionen denkt, einmal setup und einmal loop: setup, wo alles initialisiert wird; und loop, das eigentliche Programm, das in Endlosschleife durchläuft.

Vorher müssen wir noch konfigurieren, wie man das Programm auf das Einplatinensystem bekommt.

Wir gehen auf Debug → Debug Configuration.

Dann wählen wir hier unsere Debug Configuration aus: auge-versuch.configuration

und wählen dann beim Debugger den Adapter → ST-Link aus und als Port → SWD (Serial Wire Debugger)

Jetzt können wir das Programm übersetzen lassen, (Build im englischen, bzw. Projekt → Build) und dann flashen (Programm übertragen auf das System), zu finden über den Button Flash bzw. Flash → Programm Download.

Das Programm ist das Simpelste was man machen kann... es macht gar nichts. Aber es ist ein guter Versuch, die Entwicklungsumgebung zu testen ob überhaupt was erzeugt wird, oder ob was mit den Tools nicht stimmt.

So, und als typischer Vorführeffekt kam es natürlich am AUGE-Treffen dazu, dass ich stundenlang probiert habe, wieso ich keine Daten auf das Board bekam. Hatte es vorher auf einem anderen Rechner programmiert gehabt. Nach der Befragung des Orakels von Google kam die Empfehlung, dass man keine Virtuellen CD-Laufwerke haben sollte, damit es klappt. Der Empfehlung habe ich natürlich nicht Folge geleistet, sondern mir erst die Erfahrung von Linux zu Nutze gemacht, wo empfohlen wird, dass man das ST-Link V1 (Version 1) über eine komische (verkrückte) SCSi-Schnittstelle ihre Daten schicken lässt. Das hatte zur Folge, dass ich probiert habe die Virtuellen CD-Laufwerke auf höhere Buchstaben zu legen, so dass das ST-Link als erstes SCSI-Laufwerk erkannt wird. Plötzlich ging der Datentransfer.....

Die einzelnen Module bzw. Funktionsbibliotheken ( .h ) müssen C-typisch dann per #include in den Text  rein.

Und so sah dann das Endprodukt aus: Benötigte Module, RCC, GPIO, ADC (Analog Digital Converter), USART (Universal Serial Asynchron Receive  Transmitter, Universelle Serielle Schnittstelle)


#include <stm32f10x_rcc.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_adc.h>
#include <stm32f10x_usart.h>
 
int main(void)
{
 RCC_ADCCLKConfig(RCC_PCLK2_Div6);
 
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_ADC1 , ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
 
 SystemInit();
 
 GPIO_InitTypeDef GPIO_C_Init;
 GPIO_C_Init.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_C_Init.GPIO_Mode = GPIO_Mode_Out_PP;
 GPIO_C_Init.GPIO_Pin = GPIO_Pin_All;
 GPIO_Init(GPIOC, &GPIO_C_Init);
 
 GPIO_InitTypeDef GPIO_A_Init;
 GPIO_A_Init.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_A_Init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
 GPIO_A_Init.GPIO_Pin = GPIO_Pin_All;
 GPIO_Init(GPIOA, &GPIO_A_Init);
 
 GPIO_InitTypeDef GPIO_B_Init;
 GPIO_B_Init.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_B_Init.GPIO_Mode = GPIO_Mode_AIN;
 GPIO_B_Init.GPIO_Pin = GPIO_Pin_1;
 GPIO_Init(GPIOB, &GPIO_B_Init);
 
 GPIO_InitTypeDef  GPIO_InitStructure;
// für USART1 pin 9 und 10 umändern gehen.
 GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 /* Configure USART1 Tx (PA9) 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);
 
 USART_InitTypeDef USART_InitStructure;
 USART_InitStructure.USART_BaudRate            = 115200;
 USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
 USART_InitStructure.USART_StopBits            = USART_StopBits_1;
 USART_InitStructure.USART_Parity              = USART_Parity_No ;
 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
 USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
 USART_Init(USART1, &USART_InitStructure);
 USART_Cmd(USART1, ENABLE);
 
 ADC_InitTypeDef ADC_InitStructure;
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
 ADC_InitStructure.ADC_NbrOfChannel = 1;
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;
 ADC_Init(ADC1, &ADC_InitStructure);
 
 ADC_TempSensorVrefintCmd(ENABLE); // Eingebauten Temperaturfühler einschalten
 
 ADC_Cmd(ADC1, ENABLE);
                ADC_ResetCalibration(ADC1);      // Reset previous calibration
                while(ADC_GetResetCalibrationStatus(ADC1));
                ADC_StartCalibration(ADC1);       // Start new calibration (ADC must be off at that time)
                while(ADC_GetCalibrationStatus(ADC1));
 ADC_Cmd(ADC1, ENABLE);
 ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_7Cycles5);
// ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_7Cycles5);
// ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 3, ADC_SampleTime_7Cycles5);
 ADC_SoftwareStartConvCmd(ADC1, ENABLE);
 uint8_t userbutton=0; // 0 = Userbutton nicht gedrückt, 1 = Userbutton gedrückt
 uint8_t klofenster=0; // 0 = Klofenster offen, 1 = Klofenster Zu
 uint16_t analog_eingang=0;
 uint16_t eingebaut_temp_fuehler_umrechnung_forum=0;
 
 while(1)
    {
                userbutton = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);
                klofenster = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
                if ( ( userbutton == 1 || klofenster == 0 ) && analog_eingang < 2120 )
                         {
                                 GPIO_SetBits(GPIOC,GPIO_Pin_8);
                                 USART_SendData(USART1, *"A");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"T");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"D");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"T");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"6");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"6");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"6");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"\n");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                                 USART_SendData(USART1, *"\r");
                                 while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
                          }
                else GPIO_ResetBits(GPIOC,GPIO_Pin_8);
                ADC_SoftwareStartConvCmd(ADC1, ENABLE);
                analog_eingang = ADC_GetConversionValue(ADC1);
                eingebaut_temp_fuehler_umrechnung_forum=((17490-(analog_eingang/4*10))/53); //Formel in einem Forum gefunden, allerdings stand noch die +25 dazu.;
                if (analog_eingang > 500) GPIO_SetBits(GPIOC,GPIO_Pin_9); else GPIO_ResetBits(GPIOC,GPIO_Pin_9);
     }
}

​Abschließend könnte man noch sagen, dass man, um Strom zu sparen, auch nach den Datenblättern gehen sollte, und nur den Pins bzw. der Gruppe Takt/Clock gibt, die man wirklich nur braucht.