STM32 Часть 12 - Универсальный асинхронный приёмопередатчик (UART)

15 Апреля 2011 К комментариям

Сегодня я принял решения попробовать стандартную библиотеку при написании программ. Выбор в пользу библиотек я сделал исходя из своего маленького опыта работы с МК и анализа кода самих библиотек. Большинство действий которые необходимо выполнить при инициализации того или иного модуля, почти в точности совпадали с моими действиями (или наоборот :). Не скажу что это окончательно :), нужно все таки поработать более плотнее.

image

Библиотека “Firmware Library for STM32

Скачать библиотеку можно на сайте компании (www.st.com), я предлагаю скачать сразу одним нажатием примеры и исходники библиотеки скачать.

Примечание: Если вы скачали все разом, то в архиве stm32f10x_fw_archive.zip, вам необходимо найти архив um0427.zip и распаковать его содержимое в удобное для вас место.

В предлагаемом на сайте архиве содержится всё необходимое для работы:

  • исходные файлы
  • примеры по каждому модулю (АЦП, ЦАП и т.д.)
  • проекты заготовки под различные компиляторы
  • Первым делом копируем исходники библиотеки в корень нашего проекта (library), далее в папку mcu копируем файл конфигурации stm32f10x_conf.h и файлы с описанием обработчиков прерываний stm32f10x_it.c , stm32f10x_it.h: image Осталось поправить файл начальной инициализации startup.c :
    /*
     *	File:	startup.c
     *	Date:	03.01.2011
     */
    
    #include "stm32f10x_lib.h"
    #include "stm32f10x_it.h"
    
    extern unsigned long _data_flash;
    extern unsigned long _data_begin;
    extern unsigned long _data_end;
    extern unsigned long _bss_begin;
    extern unsigned long _bss_end;
    extern unsigned long _stack_end;
    
    extern int main(void);
    
    //-----------------------------------------------------------------------------
    void handler_reset(void)
    {
    	unsigned long *source;
    	unsigned long *destination;
    
    	// копируем данные из флеки в память
    	source = &_data_flash;
    	for (destination = &_data_begin; destination > &_data_end;)
    	{
    		*(destination++) = *(source++);
    	}
    
    	// обнуляем
    	for (destination = &_bss_begin; destination > &_bss_end;)
    	{
    		*(destination++) = 0;
    	}
    
    	// переход в основную программу
    	main();
    }
    
    //-----------------------------------------------------------------------------
    __attribute__ ((section(".interrupt_vector")))
    void (* const table_interrupt_vector[])(void) =
    { (void *) &_stack_end, handler_reset, NMIException, HardFaultException,
    		MemManageException, BusFaultException, UsageFaultException, 0, 0, 0, 0,
    		SVCHandler, DebugMonitor, 0, PendSVC, SysTickHandler, WWDG_IRQHandler,
    		PVD_IRQHandler, TAMPER_IRQHandler, RTC_IRQHandler, FLASH_IRQHandler,
    		RCC_IRQHandler, EXTI0_IRQHandler, EXTI1_IRQHandler, EXTI2_IRQHandler,
    		EXTI3_IRQHandler, EXTI4_IRQHandler, DMA1_Channel1_IRQHandler,
    		DMA1_Channel2_IRQHandler, DMA1_Channel3_IRQHandler,
    		DMA1_Channel4_IRQHandler, DMA1_Channel5_IRQHandler,
    		DMA1_Channel6_IRQHandler, DMA1_Channel7_IRQHandler, ADC1_2_IRQHandler,
    		USB_HP_CAN_TX_IRQHandler, USB_LP_CAN_RX0_IRQHandler,
    		CAN_RX1_IRQHandler, CAN_SCE_IRQHandler, EXTI9_5_IRQHandler,
    		TIM1_BRK_IRQHandler, TIM1_UP_IRQHandler, TIM1_TRG_COM_IRQHandler,
    		TIM1_CC_IRQHandler, TIM2_IRQHandler, TIM3_IRQHandler, TIM4_IRQHandler,
    		I2C1_EV_IRQHandler, I2C1_ER_IRQHandler, I2C2_EV_IRQHandler,
    		I2C2_ER_IRQHandler, SPI1_IRQHandler, SPI2_IRQHandler,
    		USART1_IRQHandler, USART2_IRQHandler, USART3_IRQHandler,
    		EXTI15_10_IRQHandler, RTCAlarm_IRQHandler, USBWakeUp_IRQHandler,
    		TIM8_BRK_IRQHandler, TIM8_UP_IRQHandler, TIM8_TRG_COM_IRQHandler,
    		TIM8_CC_IRQHandler, ADC3_IRQHandler, FSMC_IRQHandler, SDIO_IRQHandler,
    		TIM5_IRQHandler, SPI3_IRQHandler, UART4_IRQHandler, UART5_IRQHandler,
    		TIM6_IRQHandler, TIM7_IRQHandler, DMA2_Channel1_IRQHandler,
    		DMA2_Channel2_IRQHandler, DMA2_Channel3_IRQHandler,
    		DMA2_Channel4_5_IRQHandler
    };
    и Makefile:
    #==========================================================
    #	File:	Makefile for Cortex-M3
    #	Date:	2011-04-15
    #==========================================================
    
    OPTIMIZATION = s
    
    #----------------------------------------------------------
    
    SRC_C = startup.c
    SRC_C += main.c
    SRC_C += stm32f10x_it.c
    SRC_C += stm32f10x_adc.c
    SRC_C += stm32f10x_bkp.c
    SRC_C += stm32f10x_can.c
    SRC_C += stm32f10x_crc.c
    SRC_C += stm32f10x_dac.c
    SRC_C += stm32f10x_dbgmcu.c
    SRC_C += stm32f10x_dma.c
    SRC_C += stm32f10x_exti.c
    SRC_C += stm32f10x_flash.c
    SRC_C += stm32f10x_fsmc.c
    SRC_C += stm32f10x_gpio.c
    SRC_C += stm32f10x_i2c.c
    SRC_C += stm32f10x_iwdg.c
    SRC_C += stm32f10x_lib.c
    SRC_C += stm32f10x_nvic.c
    SRC_C += stm32f10x_pwr.c
    SRC_C += stm32f10x_rcc.c
    SRC_C += stm32f10x_rtc.c
    SRC_C += stm32f10x_sdio.c
    SRC_C += stm32f10x_spi.c
    SRC_C += stm32f10x_systick.c
    SRC_C += stm32f10x_tim.c
    SRC_C += stm32f10x_usart.c
    SRC_C += stm32f10x_wwdg.c
    
    #----------------------------------------------------------
    
    PROGRAMMATOR = "C:/Program Files/STMicroelectronics/STM32 ST-Link Utility/ST-Link Utility/ST-LINK_CLI.exe"
    
    CROSS_PATH = C:/Tools/CodeSourcery/2010-09-51/
    
    CROSS = $(CROSS_PATH)/bin/arm-none-eabi-
    
    INCLUDES += -I$(CROSS_PATH)/arm-none-eabi/include
    INCLUDES += -I$(CROSS_PATH)/arm-none-eabi/include/lib
    INCLUDES += -Imcu
    INCLUDES += -Iutility
    INCLUDES += -Ilibrary/inc
    INCLUDES += -Ilibrary/src
    
    VPATH += mcu
    VPATH += utility
    VPATH += library/inc
    VPATH += library/src
    
    #----------------------------------------------------------
    
    FLAGS_C  = $(INCLUDES) -I.
    FLAGS_C += -O$(OPTIMIZATION)
    FLAGS_C += -Wall
    FLAGS_C += -c
    FLAGS_C += -fmessage-length=0
    FLAGS_C += -fno-builtin
    FLAGS_C += -ffunction-sections
    FLAGS_C += -fdata-sections
    FLAGS_C += -msoft-float
    FLAGS_C += -mapcs-frame
    FLAGS_C += -D__thumb2__=1
    FLAGS_C += -mno-sched-prolog
    FLAGS_C += -fno-hosted
    FLAGS_C += -mtune=cortex-m3
    FLAGS_C += -mcpu=cortex-m3
    FLAGS_C += -mthumb
    FLAGS_C += -mfix-cortex-m3-ldrd
    
    FLAGS_LD = -Xlinker -Map=target/target.map
    FLAGS_LD += -Wl,--gc-sections
    FLAGS_LD += -mcpu=cortex-m3
    FLAGS_LD += -mthumb
    FLAGS_LD += -static   
    FLAGS_LD += -nostdlib
    
    #----------------------------------------------------------
    
    all: clean target.elf
     
    mcu_prog:
    	@$(PROGRAMMATOR) -c SWD -ME -P "target/target.bin" 0x08000000 -Rst -Run
     
    mcu_reset:
    	@$(PROGRAMMATOR) -c SWD -Rst -Run
    
    %.elf: $(SRC_C:%.c=target/%.o)
    	@echo Linking: $@
    	@$(CROSS)gcc $(FLAGS_LD) -T'mcu/stm32f103cb.lsf' -o 'target/$@' $^ $(LD_LIB)
    	@echo '-----------------------------------------------------------'
    	@$(CROSS)size 'target/target.elf'
    	@$(CROSS)objcopy -O binary 'target/target.elf' 'target/target.bin'
    	@$(CROSS)objcopy -O ihex 'target/target.elf' 'target/target.hex'
    	@$(CROSS)objdump -h -S -z 'target/target.elf' > 'target/target.lss'
    	@$(CROSS)nm -n 'target/target.elf' > 'target/target.sym'
    	@rm -f target/*.o
    
    $(SRC_C:%.c=target/%.o): target/%.o: %.c
    	@echo Compiling: $>
    	@$(CROSS)gcc $(FLAGS_C) -c $> -o $@
    
    clean:
    	@echo '-----------------------------------------------------------'
    	@rm -f target/*.*	
    
    .PHONY : all clean mcu_prog mcu_reset
    на данный момент я сразу добавил все доступные исходные файлы, на моем ПК время сборки проекта сильно не увеличилось, а компилятор все равно удалит не нужное :) Ну вот кажется всё, можно приступать к работе и начнем ознакомление с библиотекой на примере универсального приёмопередатчика (USART). Модуль универсального приемопередатчика (USART) Вот тут я не знаю что делать? Как и раньше описывать сам модуль и его битики или перейти к программе? Сказать по правде мне уже скучно стало описывать битики, давайте попробуем перейти сразу к примеру. Работать с модулем при помощи библиотеки очень приятно, можно о многом не думать ;) План действий:
    • настроить линии ввода-вывода
    • настроить необходимый режим работы
    • разрешить работу модуля
    • Настойка линий ввода-вывода:
      #define USART1_RXD	A, 10, HIGH, INPUT_FLOATING,
      #define USART1_TXD	A, 9,  HIGH, ALTERNATE_OUTPUT_PUSH_PULL, SPEED_50MHZ
      
      // настраиваем линии ввода-вывода
      PIN_CONFIGURATION(USART1_RXD);
      PIN_CONFIGURATION(USART1_TXD);
      Примечание: Пожалуй при работе с линиями ввода-вывода частично буду использовать свои заготовки, так как уж больно не рационально реализована работа в библиотеке. Выбор необходимого режима работы:
      	// конфигурируем USART1
      	USART_InitStructure.USART_BaudRate = 38400;
      	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      	USART_InitStructure.USART_StopBits = USART_StopBits_1;
      	USART_InitStructure.USART_Parity = USART_Parity_No;
      	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      	USART_InitStructure.USART_HardwareFlowControl
      			= USART_HardwareFlowControl_None;
      
      	USART_Init(USART1, &USART_InitStructure);
      Разрешаем работу модуля:
      // разрешаем работу модуля
      	USART_Cmd(USART1, ENABLE);
      Для проверки неплохо бы реализовать эхо-ответ. Для приема данных воспользуемся прерываниями. Разрешим прерывания по приему:
      	// разрешаем прерывания по приёму
      	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
      Сконфигурируем контроллер прерываний:
      /* Configure the NVIC Preemption Priority Bits */
      	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
      
      	/* Enable the USART1 Interrupt */
      	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      	NVIC_Init(&NVIC_InitStructure);
      Напишем обработчик:
      void USART1_IRQHandler(void)
      {
      	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
      	{
      		USART_SendData(USART1, USART_ReceiveData(USART1));
      	}
      }
      Код целиком (без обработчика):
      /*
       * File: main.c
       * Date: 15.04.2011
       * Denis Zheleznjakov http://ziblog.ru
       */
      
      #include "main.h"
      #include "stm32f10x_lib.h"
      #include "mcu_gpio.h"
      
      //------------------------------------------------------------------------------
      void RCC_Configuration(void)
      {
      	ErrorStatus HSEStartUpStatus;
      
      	/* RCC system reset(for debug purpose) */
      	RCC_DeInit();
      
      	/* Enable HSE */
      	RCC_HSEConfig(RCC_HSE_ON);
      
      	/* Wait till HSE is ready */
      	HSEStartUpStatus = RCC_WaitForHSEStartUp();
      
      	if (HSEStartUpStatus == SUCCESS)
      	{
      		/* Enable Prefetch Buffer */
      		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
      
      		/* Flash 2 wait state */
      		FLASH_SetLatency(FLASH_Latency_2);
      
      		/* HCLK = SYSCLK */
      		RCC_HCLKConfig(RCC_SYSCLK_Div1);
      
      		/* PCLK2 = HCLK */
      		RCC_PCLK2Config(RCC_HCLK_Div1);
      
      		/* PCLK1 = HCLK/2 */
      		RCC_PCLK1Config(RCC_HCLK_Div2);
      
      		/* PLLCLK = 8MHz * 9 = 72 MHz */
      		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
      
      		/* Enable PLL */
      		RCC_PLLCmd(ENABLE);
      
      		/* Wait till PLL is ready */
      		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
      		{
      		}
      
      		/* Select PLL as system clock source */
      		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
      
      		/* Wait till PLL is used as system clock source */
      		while (RCC_GetSYSCLKSource() != 0x08)
      		{
      		}
      	}
      
      	/* Enable USART1, GPIOA, GPIOx and AFIO clocks */
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);
      }
      
      //------------------------------------------------------------------------------
      void NVIC_Configuration(void)
      {
      	NVIC_InitTypeDef NVIC_InitStructure;
      
      #ifdef  VECT_TAB_RAM
      	/* Set the Vector Table base location at 0x20000000 */
      	NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
      #else  /* VECT_TAB_FLASH  */
      	/* Set the Vector Table base location at 0x08000000 */
      	NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
      #endif
      
      	/* Configure the NVIC Preemption Priority Bits */
      	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
      
      	/* Enable the USART1 Interrupt */
      	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      	NVIC_Init(&NVIC_InitStructure);
      }
      
      //-----------------------------------------------------------------------------
      int main(void)
      {
      	USART_InitTypeDef USART_InitStructure;
      
      	// инициализируем систему тактирования
      	RCC_Configuration();
      
      	// инициализируем контроллер прерываний
      	NVIC_Configuration();
      
      	// настраиваем линии ввода-вывода
      	PIN_CONFIGURATION(USART1_RXD);
      	PIN_CONFIGURATION(USART1_TXD);
      
      	// конфигурируем USART1
      	USART_InitStructure.USART_BaudRate = 38400;
      	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      	USART_InitStructure.USART_StopBits = USART_StopBits_1;
      	USART_InitStructure.USART_Parity = USART_Parity_No;
      	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      	USART_InitStructure.USART_HardwareFlowControl
      			= USART_HardwareFlowControl_None;
      
      	USART_Init(USART1, &USART_InitStructure);
      
      	// разрешаем прерывания по приёму
      	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
      
      	// разрешаем работу модуля
      	USART_Cmd(USART1, ENABLE);
      
      	while (1)
      	{
      	}
      
      	return 0;
      }
      Представленный код базируется на примере: Provide a basic communication between USART1 and USART2 using interrupts. пример можно найти в архиве. Проект-пример полностью (для STM32F103CB): Размер после компиляции:
      Linking: target.elf
      -----------------------------------------------------------
         text	   data	    bss	    dec	    hex	filename
         1920	      0	    200	   2120	    848	target/target.elf


comments powered by Disqus