Forum: Mikrocontroller und Digitale Elektronik USART mit STM32 Discovery


von Stefan S. (v0od0o)


Lesenswert?

Hallo zusammen,
ich mache gerade meine ersten Schritte mit einem STM32 Discovery Board 
nach der Methode Learning by Copying. Aktuell bin ich mit dem Versuch 
beschäftigt, über USART ein paar Bytes vom uC an den PC zu schicken. Als 
Entwicklungsumgebung nutze ich Atollic, und da mein Notebook keinen 
seriellen Port hat, verwende ich so einen fertigen RS232-To-USB-Adapter. 
Zugriff auf die serielle Schnittstelle erfolgt dann einfach und 
unkompliziert über MATLAB.

Das Problem ist nur: es funktioniert nicht. Zwar empfängt MATLAB nur 
dann etwas, wenn ich etwas sende - was schon einmal zeigt, dass es nicht 
gar nicht tut, allerdings kommt hinten nicht das raus, was ich vorne 
reingeschickt habe.

Wenn ich also z.B. fünf Nullbytes schicke und danach acht mal FF, dann 
kommt folgendes am anderen Ende an:

00000000
11111111
11111111
11111110
11111110
00000010
00001000
00010000
01000000
10000000
00000000
00000000
00000000
00000001
00000000

Wenn ich dann die gleiche Sequenz wieder durchlaufen lasse (stets vom 
Debugger aufgehalten, damit ich nachschauen kann, was es denn geworden 
ist), dann erhalte ich reproduzierbar dieses:

11111110
11111110
11111110
11111110
00000010
00001000
00010000
01000000
10000000
00000000
00000000
00000000
00000001
00000000

Auf einer anderen Seite habe ich schon gelesen, dass es da irgendein 
Problem mit einer bereits kompilierten Lib gibt, die möglicherweise 
dafür sorgt, dass der STM mit einer falschen Baudrate sendet. In den 
mittigen Bytes sieht es ja auch so aus, als müsste pro Byte etwa ein Bit 
mehr gelesen werden. Allerdings verändert ein Erhöhen der 
MATLAB-Baudrate auf 10800 das Ergebnis nicht. (Vielleicht tut MATLAB 
auch nur so, als könnte es jede beliebige Baudrate einstellen und rundet 
in Wirklichkeit auf den nächsten üblichen Wert).

In jedem Fall ist mir unerklärlich, warum die Empfangsdaten im Prinzip 
beinahe dem Inversen der Sendedaten entsprechen. Ich meine, selbst wenn 
die Pegel leicht unterschiedlich sein sollten, weil sich der uC eher zu 
3V hingezogen fühlt und der USB-Adapter eher zu 5V  -  da drehen sich 
doch nicht die Logikwerte, oder!?

Mit anderen Worten: Hülfe!

Hier noch mein aufgrund des C&P-Bastelstadiums etwas ungeordneter 
STM32-Code:
1
#include "stm32f10x.h"
2
u16 ADC_Data;
3
4
5
void Usart1Init(void);
6
void Usart1Put(uint8_t ch);
7
8
void ADConverter_Init( void )
9
    {
10
    ADC_InitTypeDef  ADC_InitStructure;
11
    GPIO_InitTypeDef GPIO_InitStructure;
12
13
    // Enable PORT clock
14
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
15
16
    /* Configure pin as analog input ---------------*/
17
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
18
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
19
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
20
    GPIO_Init(GPIOC, &GPIO_InitStructure);
21
22
    /* Enable ADC1 clock */
23
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE );
24
25
    /* ADC1 Configuration ------------------------------------------------------*/
26
    ADC_InitStructure.ADC_Mode                = ADC_Mode_Independent;
27
    ADC_InitStructure.ADC_ScanConvMode        = DISABLE;
28
    ADC_InitStructure.ADC_ContinuousConvMode  = DISABLE;
29
    ADC_InitStructure.ADC_ExternalTrigConv    = ADC_ExternalTrigConv_None;
30
    ADC_InitStructure.ADC_DataAlign           = ADC_DataAlign_Right;
31
    ADC_InitStructure.ADC_NbrOfChannel        = 1;
32
    ADC_Init( ADC1, &ADC_InitStructure );
33
34
    /* ADC1 Regular Channel 14 */
35
    ADC_RegularChannelConfig( ADC1, ADC_Channel_14,  1, ADC_SampleTime_239Cycles5);
36
37
    /* Enable ADC1 external trigger conversion */
38
    ADC_ExternalTrigConvCmd( ADC1, ENABLE );
39
40
    /* Enable ADC1  */
41
    ADC_Cmd(ADC1, ENABLE);
42
43
    /* Enable ADC1 reset calibaration register */
44
    ADC_ResetCalibration(ADC1);
45
46
    /* Check the end of ADC1 reset calibration register */
47
    while(ADC_GetResetCalibrationStatus(ADC1));
48
49
    /* Start ADC1 calibaration */
50
    ADC_StartCalibration(ADC1);
51
52
    /* Check the end of ADC1 calibration */
53
    while(ADC_GetCalibrationStatus(ADC1));
54
55
    }
56
57
u16 Get_Measure()
58
    {
59
    // Start ADC1 Software Conversion
60
    ADC_SoftwareStartConvCmd( ADC1, ENABLE );
61
62
     // Wait for end of conversion
63
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
64
65
    // Return the conversion value
66
    return (ADC_GetConversionValue(ADC1));
67
    }
68
69
70
/* Private function prototypes -----------------------------------------------*/
71
void RCC_Configuration(void);
72
void GPIO_Configuration(void);
73
void Delay(__IO uint32_t nCount);
74
void start_dma(uint32_t *sintable);
75
76
/* Private functions ---------------------------------------------------------*/
77
78
/**
79
  * @brief   Main program.
80
  * @param  None
81
  * @retval None
82
  */
83
int main(void)
84
{
85
86
87
  RCC_Configuration();
88
89
  /* Enable GPIOx Clock */
90
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
91
92
  /* Initialise LEDs LD3&LD4, both off */
93
  GPIO_DeInit(GPIOC);
94
95
  ADConverter_Init();
96
97
98
  Usart1Init();
99
100
101
  /* main while */
102
  while(1)
103
  {
104
    ADC_Data = Get_Measure();
105
106
    Usart1Put(0x00);
107
    Usart1Put(0x00);
108
    Usart1Put(0x00);
109
    Usart1Put(0x00);
110
    Usart1Put(0x00);
111
    Usart1Put(0xFF);
112
    Usart1Put(0xFF);
113
    Usart1Put(0xFF);
114
    Usart1Put(0xFF);
115
    Usart1Put(0xFF);
116
    Usart1Put(0xFF);
117
    Usart1Put(0xFF);
118
    Usart1Put(0xFF);
119
    Delay(10);
120
121
  }
122
}
123
124
/**
125
  * @brief  Inserts a delay time.
126
  * @param  nTime: specifies the delay time length, in milliseconds.
127
  * @retval None
128
  */
129
void Delay(uint32_t nTime)
130
{
131
  uint32_t TimingDelay = nTime;
132
  uint32_t i;
133
134
  while(TimingDelay != 0){
135
    i = 1000;
136
    while( i > 0 ){
137
      i--;
138
    }//*/
139
    TimingDelay--;
140
  }
141
}
142
143
/**
144
  * @brief  Decrements the TimingDelay variable.
145
  * @param  None
146
  * @retval None
147
  */
148
149
void RCC_Configuration(void)
150
{
151
  /* RCC system reset(for debug purpose) */
152
  RCC_DeInit();
153
154
  /* Enable HSE */
155
  RCC_HSEConfig(RCC_HSE_ON);
156
157
  /* Wait till HSE is ready */
158
  ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp();
159
160
  if(HSEStartUpStatus == SUCCESS)
161
  {
162
    /* Enable Prefetch Buffer */
163
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
164
165
    /* Flash 2 wait state */
166
    FLASH_SetLatency(FLASH_Latency_0);
167
168
    /* HCLK = SYSCLK */
169
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
170
171
    /* PCLK2 = HCLK */
172
    RCC_PCLK2Config(RCC_HCLK_Div1);
173
174
    /* PCLK1 = HCLK/2 */
175
    RCC_PCLK1Config(RCC_HCLK_Div1);
176
177
    /* ADCCLK = PCLK2/4 */
178
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);
179
180
    /* PLLCLK = 8MHz * 7 = 56 MHz */
181
    //RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
182
183
    /* PLLCLK = (8MHz/2) * 6 = 24 MHz */
184
        RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div2);
185
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_6);
186
187
    /* Enable PLL */
188
    RCC_PLLCmd(ENABLE);
189
190
    /* Wait till PLL is ready */
191
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
192
    {
193
    }
194
195
    /* Select PLL as system clock source */
196
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
197
198
    /* Wait till PLL is used as system clock source */
199
    while(RCC_GetSYSCLKSource() != 0x08)
200
    {
201
    }
202
  }
203
204
/* Enable peripheral clocks --------------------------------------------------*/
205
  /* Enable DMA1 and DMA2 clocks */
206
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
207
208
  /* Enable ADC1, ADC2, ADC3 and GPIOC clocks */
209
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
210
}
211
212
void Usart1Init(void)
213
214
{
215
216
GPIO_InitTypeDef GPIO_InitStructure;
217
USART_InitTypeDef USART_InitStructure;
218
USART_ClockInitTypeDef USART_ClockInitStructure;
219
220
//enable bus clocks
221
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
222
223
//Set USART1 Tx (PA.09) as AF push-pull
224
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
225
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
226
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
227
GPIO_Init(GPIOA, &GPIO_InitStructure);
228
229
//Set USART1 Rx (PA.10) as input floating
230
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
231
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
232
GPIO_Init(GPIOA, &GPIO_InitStructure);
233
USART_ClockStructInit(&USART_ClockInitStructure);
234
USART_ClockInit(USART1, &USART_ClockInitStructure);
235
236
USART_InitStructure.USART_BaudRate = 9600;
237
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
238
USART_InitStructure.USART_StopBits = USART_StopBits_1;
239
USART_InitStructure.USART_Parity = USART_Parity_No ;
240
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
241
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
242
243
//Write USART1 parameters
244
USART_Init(USART1, &USART_InitStructure);
245
246
//Enable USART1
247
USART_Cmd(USART1, ENABLE);
248
}
249
250
void Usart1Put(uint8_t ch)
251
{
252
    USART_SendData(USART1, (uint8_t) ch);
253
    //Loop until the end of transmission
254
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
255
    {
256
    }
257
}

von RP6Conrad (Gast)


Lesenswert?

Hasst du auch noch ein Level-converter um von 3 Volt (UART Discovery) 
nach +/-13 V RS232 Level (PC)  zu schalten ?

von Stefan S. (v0od0o)


Lesenswert?

Hallo RP6Conrad,
Nein, habe ich nicht. Allerdings versorgt sich der USB-Adapter eben über 
den USB-Port, d.h. knappe 5 Volt. Zudem sende ich momentan nur von uC zu 
PC und nicht anders herum, sodass der Pegel auf PC-Seite kaum relevant 
sein sollte, solange sich der uC an den Standard hält.

von Robert (Gast)


Lesenswert?

Hast Du

#define PLL_M      8
und
HSE_VALUE = 8000000

mal geändert?

von Noname (Gast)


Lesenswert?

RP6Conrad:
>Hasst du auch noch ein Level-converter um von 3 Volt (UART Discovery)
>nach +/-13 V RS232 Level (PC) zu schalten ?

Stefan S.:
>Nein, habe ich nicht. Allerdings versorgt sich der USB-Adapter eben über
>den USB-Port, d.h. knappe 5 Volt. Zudem sende ich momentan nur von uC zu
>PC und nicht anders herum, sodass der Pegel auf PC-Seite kaum relevant
>sein sollte, solange sich der uC an den Standard hält.

Ich kenne nun nicht alle Discovery Boards, nur das Discovery STM32F1 
(welches hast Du denn Stefan?), aber soweit ich weiss haben die keinen 
Pegelwandler an Board.

Inwiefern Deine Antwort, Stefan, die von RP6Conrad gestellte Frage 
beantwortet ist mir nicht klar. Denn es bleiben folgende Tatsachen zu 
bedenken:
1. Der USART1 des STM gibt 0V/3,3V aus und sein Eingang erwartet 
0V/3,3V. Darüber hinaus ist gerade dieser Eingang nicht 5V tolerant, 
ganz zu schweigen von +/- 13V.
2. Wenn also der RS232-USB Converter an seinem RX-Eingang nur 0V/3,3V 
sieht dann kann das unter Umständen als Pegelwechsel verstanden werden 
oder auch nicht. Das hängt von der konkreten Schaltung des Eingangs ab. 
Eigentlich sollen dort die +/- 13V zu sehen sein.
3. Die Pegel werden an den Ausgängen des STM invertiert ausgegeben resp. 
invertiert am Eingang erwartet. Die üblichen Pegelwandler invertieren 
nämlich. Das würde die invertierten Daten erklären, wenn auch einzelne 
Bytes resp. Bits nicht invertiert worden sind. Das wird mit Punkt 2. 
zusammenhängen.
4. Ob der RS232/USB Wandler vom PC mit 5V versorgt wird ist für diese 
Punkte irrelevant. Das ändert nichts an den anderen Tatsachen.

Was meinst Du dazu, Stefan?

von Stefan S. (v0od0o)


Lesenswert?

@Robert:
außerhalb der main.c habe ich, soweit ich mich erinnern kann, nicht 
verändert.

@Noname:
Ah, mir scheint ich bin von einigen grundlegenden Voraussetzungen 
ausgegangen, die du gerade als grundlegend falsch herausgestellt hast. 
Wenn ich die ganze Zeit invertierte Signale an den PC schicke, dann kann 
auch nicht viel dabei herauskommen, da ja nicht einmal die Start- und 
Stoppbits richtig erkannt werden können, selbst wenn es die 
Pegelprobleme nicht gäbe. Dann werd ich mich wohl mal wieder in die 
Bastelecke zurückziehen. Vielen Dank!

PS: mein Controller ist ein STM32F103 oder so und die Pins von USART1 
sind als 5V-tolerant angegeben.

von Noname (Gast)


Lesenswert?

>mein Controller ist ein STM32F103 oder so und die Pins von USART1
>sind als 5V-tolerant angegeben.

Du redest wahrscheinlich vom Discovery VL.
Aufgepasst. Der 103 ist der Debugger/Flasher der über USB an den PC 
angeschlossen wird. Das ist nicht der Prozessor auf dem Dein Programm 
läuft. Auf dem Discovery VL ist ein STM32F100 der eigentliche 
Anwendungsprozessor.

Wie auch immer: Auch bei dem F100 sind die USART1 Pins fünf Volt 
tolerant. Da habe ich was falsches geschrieben.

von Stefan S. (v0od0o)


Lesenswert?

Achso ja, steht sogar drauf wenn man genau guckt. Ich hatte gedacht, das 
F100 wäre der Oberbegriff und nicht der eigentlich richtige Controller. 
Aber naja. Praktischerweise sind ja die Dokumentationen für F10x - 
zumindest jene, die mir bisher über den Weg gelaufen sind.

Joa, VL ist richtig. Wenn man "STM32 Discovery" in die Google 
Bildersuche eingibt, sieht aber eh alles gleich aus - somit seh ich da 
auf den ersten Blick kein Unterscheidungsmerkmal zu etwaigen anderen 
STM32 Discovery-Boards.

von Robert (Gast)


Lesenswert?

Robert schrieb

> Hast Du
>
>
>
> #define PLL_M      8
>
> und
>
> HSE_VALUE = 8000000
>
>
>
> mal geändert?

Sorry, da habe Ich das Board verwechselt.
Das bezieht sich auf STM32F4 Discovery.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.