Моя очередь моргать светодиодами STM32VL-Discovery

Все моргают, вот и мне тоже захотелось. А чтобы хоть немного отличалось от других, решил управлять процессом моргания с компьютера.
картинка для заголовка

Собственно, код мало чем отличается от опубликованных GYUR22, т.к. мы используем стандартные библиотеки. Коннектимся через преобразователь на FT232RL (ссылка на его описание у DI).
Программа:

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_exti.h"
#include "misc.h"

#define LED_PORT GPIOC
#define LED_GREEN GPIO_Pin_8
#define LED_BLUE GPIO_Pin_9

ErrorStatus HSEStartUpStatus;
EXTI_InitTypeDef EXTI_InitStructure;

void SetupClock(void);
void NVIC_Configuration(void);
void EXTI0_IRQHandler(void);
void UARTSend(const uint16_t *pucBuffer, unsigned long ulCount);

uint16_t buff=0xA0;


USART_InitTypeDef USART_InitTypeDef1={
		115200,
		USART_WordLength_8b,
		USART_StopBits_1,
		USART_Parity_No,
		(USART_Mode_Rx | USART_Mode_Tx ),
		USART_HardwareFlowControl_None
};



void uart_init(){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA |  RCC_APB2Periph_USART1,ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	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);

	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	USART_Init(USART1,&USART_InitTypeDef1);
	USART_Cmd(USART1,ENABLE);

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	  GPIO_Init(GPIOA, &GPIO_InitStructure);
	  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
}

void LEDsInit()
{
		  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
		  GPIO_InitTypeDef GPIO_InitStructure;
		/* Светодиоды на PC8, PC9          */
		  GPIO_InitStructure.GPIO_Pin   = LED_GREEN | LED_BLUE;
		  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
		  GPIO_Init(LED_PORT, &GPIO_InitStructure);
}

void EXTI_Configuration(void)
{
  EXTI_InitTypeDef EXTI_InitStructure;
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}

int main(void)
{
	SetupClock();
	NVIC_Configuration();
	LEDsInit();
	uart_init();
	EXTI_Configuration();

	while(1)
	{
         //
        }
}

void PrintChar(char c){
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
	USART_SendData(USART1, c & 0x1FF); //transmite
}

void SetupClock()
{
      RCC_DeInit ();
      RCC_HSEConfig (RCC_HSE_ON);

      while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);

      RCC_HCLKConfig   (RCC_SYSCLK_Div1);
      RCC_PCLK2Config  (RCC_HCLK_Div1);
      RCC_PCLK1Config  (RCC_HCLK_Div1);
     // RCC_ADCCLKConfig (RCC_PCLK2_Div4);

      /* PLLCLK = 8MHz * 2 = 16 MHz                                           */
      RCC_PLLConfig (RCC_PLLSource_PREDIV1, RCC_PLLMul_2);

      while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

      RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK);

      while (RCC_GetSYSCLKSource() != 0x08);

}

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

    //
    // Configure one bit for preemption priority
    //
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
}

void EXTI0_IRQHandler(void)
{
	EXTI_ClearITPendingBit(EXTI_Line0);
	GPIO_WriteBit(LED_PORT, LED_BLUE, Bit_SET);

	//UARTSend("on", 2);

	UARTSend(&buff, sizeof(buff));
	buff++;
}

void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != (u16)RESET)
	{
    		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    		uint16_t i= USART_ReceiveData(USART1);

			if (i=='y')
			{
				GPIO_WriteBit(LED_PORT, LED_GREEN, Bit_SET);
			}
			else if (i=='n')
			{
				GPIO_WriteBit(LED_PORT,LED_GREEN, Bit_RESET);
			}
			UARTSend(&i,1);
	}
}

void UARTSend(const uint16_t *pucBuffer, unsigned long ulCount)
{
    while(ulCount--)
    {
        USART_SendData(USART1, (uint16_t) *pucBuffer++);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {
        }
    }
}


Прерывания возникают по нажатию на кнопку USER, а также по приему UART1. В обработчике шлем ответ. Все просто.

Теперь касаемо программы для компьютера.
Так как тут все больше для компа пишут либо на дельфи, либо на шарпе, то не будем отходить от традиции. Накидаем на шарпе. WPF. Требует .NET Framework 4.0.

В программе можно выбирать COM-порт и задавать основные его параметры (скорость, стоповые биты, длину посылки, четность). После выбора параметров, они сразу применяются, если это возможно.
Вот основной код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;

namespace ComLED
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private static SerialPort comPort;
        private delegate void UpdateDelegate(TextBlock messages);
        private static Timer RefreshTimer;

        public MainWindow()
        {
            InitializeComponent();
            comPort = new SerialPort();



            foreach (var pNames in SerialPort.GetPortNames())
            {
                MenuItem mi = new MenuItem();
                mi.Header = pNames.ToString();
                mi.IsCheckable = true;
                mi.Checked += ports_Checked;
                ports.Items.Add(mi);
            }

            foreach(var buf in Enum.GetValues(typeof(StopBits)))
            {
                MenuItem mi = new MenuItem();
                mi.Header = buf.ToString();
                mi.IsCheckable = true;
                mi.Checked += stopBit_Checked;

                stopBit.Items.Add(mi);
            }

            foreach (var buf in Enum.GetValues(typeof(Parity)))
            {
                MenuItem mi = new MenuItem();
                mi.Header = buf.ToString();
                mi.IsCheckable = true;
                mi.Checked += parity_Checked;

                parity.Items.Add(mi);
            }

            comPort.PortName = "COM7";
            comPort.BaudRate = 115200;
            comPort.DataBits = 8;
            comPort.StopBits = StopBits.One;
            comPort.Parity = Parity.None;

            comPort.WriteTimeout = 500;
            comPort.ReadTimeout = 500;

            RefreshTimer = new Timer();
            RefreshTimer.Interval = 1000;
            RefreshTimer.Elapsed += new ElapsedEventHandler(RefreshTimer_Elapsed);
            //  RefreshTimer.Start()

            comPort.Open();
        }

        void portsUnchecked()
        {
            for (int i = 0; i < ports.Items.Count; i++)
            {
                (ports.Items[i] as MenuItem).IsChecked = false;
            }
        }

        void stopBitUnchecked()
        {
            for (int i = 0; i < stopBit.Items.Count; i++)
            {
                (stopBit.Items[i] as MenuItem).IsChecked = false;
            }
        }

        void parityUnchecked()
        {
            for (int i = 0; i < parity.Items.Count; i++)
            {
                (parity.Items[i] as MenuItem).IsChecked = false;
            }
        }

        void RefreshTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.SystemIdle, new UpdateDelegate(Refresh), tb);
            //Refresh();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (comPort.IsOpen)
            {
                comPort.WriteLine("y");
            }

            this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.SystemIdle, new UpdateDelegate(Refresh), tb);
          //  Refresh(tb);
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            if (comPort.IsOpen)
            {
                comPort.WriteLine("n");
            }

            this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.SystemIdle, new UpdateDelegate(Refresh), tb);
          //  Refresh(tb);
        }

        private void Refresh(TextBlock textBlock)
        {
            try
            {
                if (comPort.IsOpen)
                {
                    textBlock.Text = comPort.ReadLine();
                }

                if (textBlock.Text == "y")
                {
                    LED.Fill = new SolidColorBrush(Colors.Green);
                }
                else if (textBlock.Text == "n")
                {
                    LED.Fill = new SolidColorBrush(Colors.Gray);
                }
                else
                {
                    LED.Fill = new SolidColorBrush(Colors.YellowGreen);
                }
            }
            catch (TimeoutException)
            {
                //
            }

        }

        private void ports_Checked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (comPort.IsOpen)
                {
                    portsUnchecked();

                    comPort.Close();
                    comPort.PortName = (sender as MenuItem).Header.ToString();
                    (sender as MenuItem).IsChecked = true;
                    comPort.Open();
                }
            }
            catch (TimeoutException)
            {
                //
            }

        }

        private void stopBit_Checked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (comPort.IsOpen)
                {
                    stopBitUnchecked();

                    StopBits buff = StopBits.One;
                    if (StopBits.TryParse((sender as MenuItem).Header.ToString(),out buff))
                    {
                    comPort.Close();
                    comPort.StopBits = buff;
                    (sender as MenuItem).IsChecked = true;
                    comPort.Open();
                    }
                }
            }
            catch (TimeoutException)
            {
                //
            }

        }

        private void parity_Checked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (comPort.IsOpen)
                {
                    parityUnchecked();

                    Parity buff = Parity.Even;
                    if (Parity.TryParse((sender as MenuItem).Header.ToString(), out buff))
                    {
                        comPort.Close();
                        comPort.Parity = buff;
                        (sender as MenuItem).IsChecked = true;
                        comPort.Open();
                    }
                }
            }
            catch (TimeoutException)
            {
                //
            }

        }

        private void speed_KeyDown(object sender, KeyEventArgs e)
        {
            int res;
            if (e.Key == Key.Enter)
            {
                if (Int32.TryParse(speed.Text, out res))
                {
                    comPort.Close();
                    comPort.BaudRate = res;
                    comPort.Open();
                }
                else
                {
                    speed.Text = comPort.BaudRate.ToString();
                    return;
                }
            }
        }

        private void wordLength_KeyDown(object sender, KeyEventArgs e)
        {
            int res;
            if (e.Key == Key.Enter)
            {
                if (Int32.TryParse(wordLength.Text, out res) && (res >= 5 && res <= 8))
                {
                        comPort.Close();
                        comPort.DataBits = res;
                        comPort.Open();
                }
                else
                {
                    wordLength.Text = comPort.DataBits.ToString();
                    return;
                }
            }
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }
    }
}


скрин

скрин частью меню
Ну тут все тоже просто. По нажатию на любую из кнопок отсылаем символ и смотрим, что пришло в ответ. В зависимости от символа, красим эллипс. Сам символ выводим в TextBlock.
Если кому нужно, то могу перенести на другую версию Framework, а также вынести параметры по умолчанию в конфигурационный файл (а-ля метапрограммирование), чтобы к коду не был привязан.
Позже выложу видео с подключенным ключиком на MOSFET. Видео снимал на телефон, поэтому качество соответствующее.



На этом пока все.
  • 0
  • 30 августа 2011, 16:17
  • Frolls
  • 3
Файлы в топике: ComLED.zip, CommUSART.zip, stm32f10x_usart_v3_4.zip

Комментарии (26)

RSS свернуть / развернуть
WPF. Требует .NET Framework 4.0.
Да ну. в 3.5 я знакомился с впфкой, 4.0 и в помине не было.
0
Поверьте, я прекрасно знаю, в каком дотнете появился WPF. В посте не утверждал, что WPF появился именно в .NET 4. Прога собрана под 4-ый. Неужели это не очевидно?
0
вот оно че Михалыч...:)
0
А чё за платка такая вверху, с двумя TO-220 и пиримидой клеммников?
0
  • avatar
  • ploop
  • 30 августа 2011, 20:44
Это ключ на MOSFET
0
До чего громоздкий код-то… Не зря я библиотеки эти не люблю, равно как и дотнет…
0
  • avatar
  • _YS_
  • 30 августа 2011, 21:11
почти весь код на шарпе написан для того, чтобы можно было из программы выбирать COM-порт и задавать его параметры. А так все сократилось бы почти до

  comPort.PortName = "COM7";
  comPort.BaudRate = 115200;
  comPort.DataBits = 8;
  comPort.StopBits = StopBits.One;
  comPort.Parity = Parity.None;
+ обработчики нажатия на кнопки.
А по поводу использования библиотек под STM, мне так больше нравиться. Можно почти сразу сконцентрироваться на решении поставленной задачи, не лазая в даташит каждые пару минут. Не хочу поднимать очередной холивар, где-то здесь это уже было. Стараюсь почти всегда использовать стандартные библиотеки/решения, а не заниматься изобретением очередного велосипеда. Проигрыш от использования библиотек в чем-либо сомнителен в данном случае, а преждевременная оптимизация — зло (С)
0
мне так больше нравиться.

Да я уже понял. :-)
0
Почему не сделал триггерное нажатие на окружность, так вроде проще, а не тыкать то одну, то другую кнопку, к тому же разнесенные в разные части формы или планируешь девайсом ракеты запускать?)))
Шутнику палец средний паяльником припали, чтобы впредь не показывал. ;-)
0
Кнопки для наглядности, а эллипс показывает состояние светодиода на плате. Хотя да, можно и в эллипс тыкать. Могу поправить, если надо кому.
Видео перезалью, как камера зарядится :-)
0
Да не, просто насчет клика на эллипс это то как бы я сделал))) А разводить кнопки имхо стоит только если боимся дребезга или случайного срабатывания. Но это мои тараканы)))
0
У меня проблемка:
void USART1_IRQHandler(void) {
	if (USART_GetITStatus(USART1, USART_IT_RXNE) ) {
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
		USART_ClearFlag(USART1, USART_FLAG_RXNE);
		GPIOC->ODR ^= GPIO_ODR_ODR8;
	};
};
Этот код почему-то срабатывает при ОТПРАВКЕ. Остальной код — всё как здесь. Что за мистика, как думаете? Наводки исключены, я тычусь на Rx осциллографом и вижу что ничего нет. Таймер рядом дёргает Tx, планировалось, что светодиод будет моргать когда я замкну Tx на Rx. Но он моргает постоянно, при отправке.
0
Покажите все-таки, как вы инициализируете UART. Есть предположение, что Вы в функции void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState) разрешили прерывания как на прием, так и на передачу
0
Не-а.
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

Я написал об этом и на форуме в теме о граблях USART'a, даже подчерпнул оттуда кое-что, но ничего не помогло. Ссылка на тему: forum.easyelectronics.ru/viewtopic.php?f=35&t=1755 (моё сообщение снизу).

Кстати, сколько у тебя весят файлы stm32f10x_usart.h и.с (в байтах) и какая у них версия? Написано в комментарии в начале файлов. У меня @version V3.5.0 @date 11-March-2011
0
Кстати, при USART_Mode = USART_Mode_Tx (только передача) или Rx (только прием) прерывание не срабатывает. Только если Tx и Rx вместе. Это наводит на мысли что как-будто где-то внутри работает режим «обратной связи», когда все переданные байты шлются обратно.
0
******************************************************************************
  * @file    stm32f10x_usart.c
  * @author  MCD Application Team
  * @version V3.4.0
  * @date    10/15/2010
  * @brief   This file provides all the USART firmware functions.
  ******************************************************************************
0

  ******************************************************************************
  * @file    stm32f10x_usart.c
  * @author  MCD Application Team
  * @version V3.4.0
  * @date    10/15/2010
  * @brief   This file provides all the USART firmware functions.
  ******************************************************************************
  ******************************************************************************
  * @file    stm32f10x_usart.h
  * @author  MCD Application Team
  * @version V3.4.0
  * @date    10/15/2010
  * @brief   This file contains all the functions prototypes for the USART 
  *          firmware library.
  ******************************************************************************

0
Откатиться что ли до 3.4.0 и проверить на ней…
0
Добавил архив к топику — stm32f10x_usart_v3_4
0
файлы от v3.4.0 не помогли, но я скачал твой проект целиком, все содержимое скопировал к себе (импортировать не удалось, каких-то плагинов не хватало, у тебя наверное Atollic TrueStudio а не чистый Eclipse как у меня?). Проект скомпилировался и заработал. Сейчас буду по каждой букве сравнивать и искать различия. Интересно прям, где будет ошибка… :)
0
Блин, ссылки на 3.4.0 либо битые, либо ведут на более свежую 3.5.0. Можешь ее скинуть куда-нибудь (на народ)? Будет ОЧЕНЬ весело, если с 3.4.0 все будет работать.
0
Я использовал CooCoxIDE.
Говорю же, что прикрепил архив с v3.4.0. Сам качал для проверки. Работает.
0
Я проверил, проблема только в main.c (в моём коде). Разницы в версиях нет, т.е. с 3.5.0 твой код работает. Ищу разницу в моём и твоём коде…
0
Нашёл, блин. Я инициализировал и включил USART CLOCK. Не зная что это такое :) Стёр эти несколько строчек и всё заработало. Я думал это какое-то тактирование самого USART'a… а что это такое на самом деле?
0
USART — Universal Synchronous/Asynchronous Receiver/Tranceiver. Скорее всего ты включил выходной клок синхронного режима. Не знаю правда почему такой результат оно дало.
0
  • avatar
  • Vga
  • 12 сентября 2011, 14:02
такой вопрос возник, почему у вас нету RCC_PLLCmd(ENABLE);?
спасибо
0
  • avatar
  • Sarog
  • 12 октября 2011, 16:34
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.