Разработка и исследование модели нейросетевого регулятора на микроконтроллере STM32F407VG

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    1,09 Мб
  • Опубликовано:
    2016-02-21
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Разработка и исследование модели нейросетевого регулятора на микроконтроллере STM32F407VG















Разработка и исследование модели нейросетевого регулятора на микроконтроллере STM32F407VG

Техническое задание

Разработать и исследовать модель нейросетевого регулятора на микроконтроллере STM32F407VG.

Введение

алгоритм программа нейросеть

В данной курсовой работе необходимо разработать алгоритм и программу на ПК двухслойной нейросети, а также аналогичную программу на микроконтроллере STM32F407VG. В программе на ПК реализовано обучение нейросети и передача весовых коэффициентов на микроконтроллер по интерфейсу связи UART.

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

Целью данной работы является разработка модели нейросети на микроконтроллере, а так же закрепление практических навыков программирования микроконтроллеров на языке С и программирования ПК на С#. Процесс подготовки предусматривает самостоятельное изучение нового материала и закрепление его с помощью практического задания.

1.     
Разработка алгоритма


Для дальнейшей работы необходимо построить следующие алгоритмы: алгоритм работы программы в целом, алгоритм обучения нейросети.

1.1    Математический алгоритм


1.1.1 Искусственные нейронные сети

Несмотря на большое разнообразие вариантов нейронных сетей, все они имеют общие черты. Так, все они, так же, как и мозг человека, состоят из большого числа связанных между собой однотипных элементов - нейронов, которые имитируют нейроны головного мозга. На рис. 1 показана схема нейрона.


Из рисунка видно, что искусственный нейрон, так же, как и живой, состоит из синапсов, связывающих входы нейрона с ядром; ядра нейрона, которое осуществляет обработку входных сигналов и аксона, который связывает нейрон с нейронами следующего слоя. Каждый синапс имеет вес, который определяет, насколько соответствующий вход нейрона влияет на его состояние.

Состояние нейрона определяется по формуле

(1)

где :

n - число входов нейрона

xi - значение i-го входа нейрона

wi - вес i-го синапса

Затем определяется значение аксона нейрона по формуле

= f(S)                                                                                                                    (2)

Где f - некоторая функция, которая называется активационной. Наиболее часто в качестве активационной функции используется сигмоид, который имеет следующий вид:

                                                                                                (3)

Основное достоинство этой функции в том, что она дифференцируема на всей оси абсцисс и имеет очень простую производную:

                                                                             (4)

При уменьшении параметра a сигмоид, становится более пологим, вырождаясь в горизонтальную линию на уровне 0,5 при a=0. При увеличении a, сигмоид приближается к функции единичного скачка.

Список других наиболее употребляемых функций активации приведен в таблице 1.

Таблица 1- Основные функций активации.

Название

Математическая запись

1

Линейная

2

Пороговая бинарная

3

Пороговая биполярная

4

Линейная ограниченная

5

Гиперболический тангенс

6

Логарифмическая

7

Радиально-базисная

8

Сигмоидная (y  [-1,1])


Обучение нейронной сети

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

Существуют два концептуальных подхода к обучению нейронных сетей: обучение с учителем и обучение без учителя. В данной курсовой работе используется метод обучения с учителем.

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

Алгоритм обратного распространения ошибки:

.        Инициализировать синаптические веса маленькими случайными значениями.

.        Выбрать очередную обучающую пару из обучающего множества; подать входной вектор на вход сети.

.        Вычислить выход сети.

.        Вычислить разность между выходом сети и требуемым выходом (целевым вектором обучающей пары).

.        Подкорректировать веса сети для минимизации ошибки (как см. ниже).

Повторять шаги с 2 по 5 для каждого вектора обучающего множества до тех пор, пока ошибка на всем множестве не достигнет приемлемого уровня.

Рассмотрим подробней 5 шаг - корректировка весов сети. Здесь следует выделить два нижеописанных случая.

Случай 1. Корректировка синаптических весов выходного слоя

Определимся, что индексом p будем обозначать нейрон, из которого выходит синаптический вес, а q - нейрон в который входит.

Введем величину δ, которая равна разности между требуемым и реальным выходами, умноженной на производную функции активации:

 (5)

Тогда, веса выходного слоя после коррекции будут равны:

(6)

где:

i - номер текущей итерации обучения;

 - величина синаптического веса, соединяющего нейрон p с нейроном q;

 - коэффициент «скорости обучения», позволяет управлять средней величиной изменения весов;

 - выход нейрона .

Случай 2. Корректировка синаптических весов скрытого слоя.

(7)

где:

 - сумма от 1 по N, N - количество нейронов выходного слоя.

Тогда, веса скрытого слоя после коррекции будут равны:

(8)

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

(9)

где  реальное выходное состояние нейрона  выходного слоя N нейронной сети при подаче на ее входы  - го образа;  - желаемое (идеальное) выходное состояние этого нейрона. Суммирование происходит по всем нейронам выходного слоя и по всем обрабатываемым сетью образам.

1.2 Разработка схем алгоритмов

Для дальнейшей работы необходимо построить следующие алгоритмы: алгоритм работы программы в целом, и алгоритм обучения нейросети. Обобщенная схема алгоритма программы, распознающей 2 класса чисел с помощью искусственной нейросети на микроконтроллере, представлена на рисунке 2.

Рисунок 2 - Обобщенная схема алгоритма программы

Алгоритм обучения нейросети представлен на рисунке 3.

Рисунок 4 - Схема алгоритма обучения нейросети

2. Разработка программы


Для запуска этой программы предварительно была записана прошивка в микроконтроллер, которая разрабатывалась в среде Keyl 4. Затем соединяются выводы PC10 и РС11 микроконтроллера с выводами Rx и Tx соответственно любого преобразователя компьютерных интерфейсов в UART, на плате с соответствующими элементами. После этого подключается USB-кабель к отладочной плате, тем самым подавая питание на микроконтроллер.

Следующим шагом является запуск программы на ПК. Для этого нужно иметь установленную версию Windows XP/Vista/7. Данная программа разрабатывалась в среде MSVisualC# 2010(Microsoft .NET Framework 4.0).

2.1 Разработка программы на ПК


Для работы использовались следующие пространства имен:

System;.Collections.Generic;.ComponentModel;.Data;.Drawing;.Text;.Windows.Forms;.Threading;.IO;.IO.Ports;

Для создания программы на ПК были использованы:

class Neyro - класс работающий с нейросетью.

class Form1 : Form - класс диалогового окна, наследуемый от стандартного класса Form.int[] Vihod(int kol, int kl) - метод, формирующий целевой вектор.void Korekt() - метод, коректирующий синапсы.void Rez() - метод вычисления результата нейросети.

public void CreateNS() - метод, создающий нейросеть.

public void Obuchenie(string file, StreamWriter sw1) - метод, обучающий нейросеть определенному классу чисел.

private void grafic() - метод, рисующий график.

Текст программы представлен в приложении А.

2.2 Разработка программы на микроконтроллер


Для создания программы на микроконтроллере STM32F407VG были использованы:

Функции:

void delay(int n) - функция задержки.

void InitUart4(void) - инициализация UART. InitPorts() - инициализация портов.InitNeyro() - инициализация и создание модели нейросети.CreateNeyro(Neyro* nr) - функция заполнения матриц весовых коэффициентов малыми случайными значениями.Res(Neyro* nr) - функция расчета выходных значений нейросети.

void Write_koef(Neyro* nr, const double *buf) - функция записи весовых коэффициентов в матрицы принятых с ПК.

void Write_vvod(Neyro* nr, const double *buf) - функция формирования входных значений нейросети принятых данных с ПК.Klass(Neyro* nr) - функция определения класса чисел по выходным значениям нейросети.

Прерывания:

void UART4_IRQHandler() - перывание по приему данных через UART интерфейс.SysTick_Handler() - прерывание по переполнению таймера SysTick.

Текст программы представлен в приложении Б.

3.     
Вычислительный эксперимент


3.1 Программа разработанная на языке С#


При запуске вызываем Windows окно. Ознакомившись, вводим данные с клавиатуры, требуемые программой. Вычислительный эксперимент представлен на рисунке 5.

Рисунок 5 - Результат работы программы, представленный в Windows окне

При неправильном использовании возникают ошибки, представленные на рисунках 6, 7.

  

Рисунок 6 - Ошибки при вводе данных

 

Рисунок 7 - Ошибки при вводе данных

 

.2 Программа, разработанная на микроконтроллер


На микроконтроллер, с заранее установленной прошивкой, требуется только лишь подать питание, подключив USB-кабель к отладочной плате, и наблюдать за результатом, так как основное управление происходит с ПК.

Вычислительный эксперимент представлен на рисунках 8, 9.

Рисунок 8 - Результат вычислительного эксперимента.

Рисунок 9 - Результат вычислительного эксперимента.

4.     
Руководство программиста

 

.1 Назначение и условия применения программы


Программа предназначена для распознавания двух классов чисел.

Для запуска этой программы необходимо иметь на компьютере установленную версию Windows XP/Vista/7. Данная программа разрабатывалась в среде MSVisualC# 2010(Microsoft .NET Framework 4.0).

4.2 Характеристика программы


.2.1 Программа для ПК

Для написания программы нам понадобились следующие команды:

Получение числовых значений из текстовых полей:= Convert.ToInt32(textBox1.Text); (cм. Приложение А)

Вывод окошка:.Show("Введите количество нейронов первого слоя");

(cм. Приложение А)

Чтение содержимого файла:= File.ReadAllLines("1-1.txt"); (cм. Приложение А)

Сброс текстбокса:.Clear(); (cм. Приложение А)

В данной программе был создан класс - class Neyro, с помощью которого создается нейросеть, и затем ведется работа с ней.

Класс содержит следующие переменные:

public double[] prom, vvod;

public double[,] w1, w2;double[] rez;int count1=0, count2=0;int neyr1, neyr2;int[] ogid; bool[] ogid1, ogid2;double k, skor;double[] err_m = new double[100]; (cм. Приложение А)

Значениям переменных neyr1, neyr2 присваивается значение количества нейронов в первом и втором слоях нейросети соответственно.

Массив vvod заполняется из файла с входными данными. Далее вычисляются значения массивов prom и rez. Массив prom - это результаты выходов нейронов первого слоя. А массив rez - результаты выходов нейросети.

Также в классе используются методы:

int[] Vihod(int kol, int kl) - метод, формирующий целевой вектор.void Korekt() - метод, коректирующий синапсы.void Rez() - метод вычисления результата нейросети.

public void CreateNS() - метод, создающий нейросеть.

public void Obuchenie(string file, StreamWriter sw1) - метод, обучающий нейросеть определенному классу чисел.

Для установки соединения по интерфейсу RS-232 использовался класс SerialPort и в частности следующие методы:() - установление соединения.() - завершение соединения.() - чтение данных, пришедших по интерфейсу RS-232.(string ) - отправка данных по интерфейсу RS-232.

Текст программы класса представлен в Приложении А.

Правильность работы класса и программы в целом подтверждена вычислительным экспериментом. (см. рисунки 5-9).

4.2.2 Программа для микроконтроллера

Программа для микроконтроллера написана на языке С. В этом языке программирования нет классов, поэтому для создания модели нейросети использовалась структура:

struct

{vvod[Amount_Vvod]; prom[Neyr1]; rez[Neyr2];w1[Amount_Vvod][Neyr1];w2[Neyr1][Neyr2]; k; ogid1[Neyr2];ogid2[Neyr2];

}Neyro;- массив входных значений нейросети.- массив выходных значений первого слоя нейросети.- массив выходных значений нейросети.- матрица весовых коэффициентов первого слоя.- матрица весовых коэффициентов второго слоя. - коэффициент активационной функции (сигмоид).- массив значений, ожидаемых на выходе, при подаче на вход чисел первого класса.- массив значений, ожидаемых на выходе, при подаче на вход чисел второго класса.

 

4.3 Обращение к программе


Для запуска программы необходимо открыть в папке «курсовой ЭВМиВС» файл «курсовой ЭВМиВС.sln» с помощью MS Visual Studio С# 2010 и нажать кнопку «Начать отладку». В результате должно появиться окно программы.

4.4    Входные и выходные данные


В предыдущей работе были подобраны оптимальные значения коэффициентов нейросети:

Количество шагов обучения - 100;

Коэффициент скорости обучения - 0,7;

Коэффициент сигмоида - 1,3;

Эффективность работы нейросети с этими параметрами так же была проверена при работе с другими классами чисел. Поэтому для данной нейросети лучше использовать именно эти значения.

В пункты: «Количество нейронов», нужно вводить целые значения. Значения коэффицентов k (коэффицент сигмоидной функции) и skor (скорость обучения) могут быть дробными.

В пункте «Обучающая выборка» нужно выбрать файлы для обучения нейросети соответствующим классам. В пунктах «Файл» выбираются файлы для экзаменационной и тестовой выборки.

В файлах экзаменационной выборки представлены 20 выборок соответствующего класса. После нажатия кнопки «Старт» будет выведен процент распознавания чисел данного класса. Если он низок и не удовлетворяет условиям, то следует вернуться к шагу обучения. Далее можно переходить к тестированию программы.

5.     
Руководство пользователя


Программа предназначена для распознавания двух классов чисел.

Для запуска программы необходимо открыть в папке «курсовой ИТПЗ 2010» файл «курсовой титп2.sln» с помощью MS Visual Studio С# 2010 и нажать кнопку «Начать отладку». В результате должно появиться окно программы.

После появления рабочего окна (рисунок 9) можно поступать к работе.

Рисунок 9 - Окно для ввода данных

В пункты: «Количество нейронов», нужно вводить целые значения. Модель нейросети на ПК может иметь любое количество нейронов как первого, так и второго слоя. Но так как в программе микроконтроллера нейросеть имеет 4 нейрона на первом слое и 2 на втором, следует вводить именно эти значения.

Значения коэффицентов k (коэффицент сигмоиды) и skor (скорость обучения) могут быть дробными.

После ввода этих значений нужно нажать кнопку «Создать сеть».

Далее в пункте «Обучающая выборка» нужно выбрать файлы для обучения нейросети и нажать на кнопку «Обучить».

После того как сеть будет обучена, появится график функции ошибки нейросети зависящий от шага обучения, а так же таблица значений ошибок при каждом шаге.

Затем следует проверить нейросеть на правильность распознавания образов. В пункте «Экзаменационная выборка» выбираются файлы первого или второго класса, в которых содержатся по 20 выборок. После нажатия кнопки «Старт» в строке «Процент» появится процент распознавания нейросетью образов выбранного класса. Если процент распознавания низкий, то следует вернуться к обучению нейросети. Если же процент удовлетворяет требованиям, то следует передать значения весовых коэффициентов на микроконтроллер. Для этого следует выбрать доступный COM-порт в выпадающем меню PortName и нажать кнопку Connect. После удачного соединения нужно нажать кнопку «Отправить коэффициенты» и дождаться полной отправки. Во время приема весовых коэффициентов на отладочной плате микроконтроллера синий светодиод будет загораться с частотой 5 Гц (в режиме ожидания - 1 Гц).

Тестовая выборка служит для того, чтобы самому убедиться в правильности работы программы. В тестовых файлах представлена одна выборка определенного класса чисел. После выбора файла можно проверить работу программы как на ПК, нажав кнопку «Результат», так и на микроконтроллере, передав числа, находящиеся в файле по RS-232. Для этого следует установить соединение с COM-портом, если это не сделано ранее, и нажать кнопку «Send to MC». Во время приема чисел, так же как и во время приема весовых коэффициентов, синий светодиод отладочной платы будет загораться с частотой 5 Гц. После обработки результатов загорается либо зеленый, либо красный светодиод. Зеленый - если удалось распознать первый класс чисел, красный - если второй. При неудачном распознавании оба светодиода будут выключены.

Заключение


Разработанная программа соответствует заданным на этапе проектирования требованиям. Во время работы над программой были улучшены навыки программирования на языке С#, а также навыки программирования микроконтроллеров. Была исследована модель нейросети созданная на микроконтроллере, которая показала хорошие результаты.

В качестве перспектив развития данной темы можно отметить такие нереализованные возможности как обучение непосредственно на микроконтроллере, подключение датчиков для формирования входных значений и непосредственное применение в какой-либо области робототехники.

Список литературы


1.      Павловская Т.А. C#. Программирование на языке высокого уровня. СПб. : Питер, 2010.

2.      Фролов А. В., Фролов Г. В. Язык С#. Самоучитель. М: ДИАЛОГ-МИФИ, 2009.- 560с.

3.       STM32F405xx, STM32F407xx, STM32F415xx and STM32F417xx advanced ARM-based 32-bit MCUs - Datasheet.

4.       ГОСТ 2.105-95 Единая система конструкторской документации. Общие требования к текстовым документам.

5.      ГОСТ 19.504-79 (СТ СЭВ 2095-80). Руководство программиста. Требования к содержанию и оформлению.

6.    ГОСТ 19.701-90 (ИСО 5807-85). ЕСПД. Схемы алгоритмов, программ, данных и систем.

Приложение

Текст программы на ПК.

Текст программы файла Form1.cs представлен на рисунке А.1.

System;System.Collections.Generic;System.ComponentModel;System.Data;System.Drawing;System.Text;System.Windows.Forms;System.Threading;System.IO;System.IO.Ports;курсовой_титп_2

{partial class Form1 : Form

{double[] x1, x2, r;number = new Random();nr;bool flag = false; //флаг создания нейросетиbool fl_pot = false; //флаг работы потоковThread pp;Thread pp1;DateTime dd;int mx = 5, my = 100; //МасштабSystem.Drawing.Graphics graphicsObj;Pen myPen1 = new Pen(System.Drawing.Color.Red, 1);Pen myPen2 = new Pen(System.Drawing.Color.Black, 1);static SerialPort sp = new SerialPort(); // com portbool flag_connect = false; //флаг соединения по ком порту Thread readThread; //поток чтения ком портаъForm1()

{.x1 = new double[200]; //числа первого класса.x2 = new double[200]; //числа второго класса.r = new double[6]; //рандомные числаsum_r = 0;(int i=0; i<200;i++)

{(int j = 0; j < 6; j++)

{[j] = number.NextDouble();_r += r[j];

}[i] = (sum_r - 3) / Math.Sqrt(0.5);[i] = Math.Round(x1[i],3)+2.5;[i] = x1[i] + 7.5;_r = 0;

}();

//обновление списка доступных ком портов.Items.AddRange(SerialPort.GetPortNames());

//установка первого доступного ком порта в список(SerialPort.GetPortNames().Length != 0)

{.Text = SerialPort.GetPortNames()[0];

}

//int aaa = sizeof(double);

}

// ///////////////////////////////////////////

// кнопка создать сетьvoid button1_Click(object sender, EventArgs e)

{neyr1, neyr2;k, skor;= true;(textBox1.TextLength != 0)

{= Convert.ToInt32(textBox1.Text); //количество нейронов первого слоя

}

{.Show("Введите количество нейронов первого слоя");;

}(textBox2.TextLength != 0)

{= Convert.ToInt32(textBox2.Text); //количество нейронов второго слоя

}

{.Show("Введите количество нейронов второго слоя");;

}(textBox9.TextLength != 0)

{= Convert.ToDouble(textBox9.Text); //коэффицент сигмоида k

}

{.Show("Введите k");;

}(textBox11.TextLength != 0)

{= Convert.ToDouble(textBox9.Text); //коэффицент скорости обучения

}

{.Show("Введите skor");;

}= new Neyro(neyr1, neyr2, k, skor); //вызываем конструктор класса.CreateNS();

//выводим резульат нейросети.Clear();(int i=0; i<neyr2;i++)

{.AppendText(Convert.ToString(Math.Round(nr.rez[i],3)) +" ");

}

}

////////////////////////////////////////////////////////////

//кнопка сбросvoid button2_Click(object sender, EventArgs e)

{.Clear();.Clear();.Clear();.Clear();.Clear();.Clear();.Text = "";.Text = "";.Text = "";.Text = "";

}

// //////////////////////////////////////

// кнопка обучить 1 классvoid button3_Click(object sender, EventArgs e)

{file;

//int kl = 1;file_osibka = "oshibka.txt";(flag == false)

{.Show("Создайте сеть");;

}(comboBox1.Text != "")

{= comboBox1.Text; //выбранный файл для обучения первого класса

}

{.Show("Выберите файл");;

}

//создаем файл для вывода ошибкиfo = new FileStream(file_osibka, FileMode.Create, FileAccess.Write, FileShare.Write);.Close();sw1 = new StreamWriter(file_osibka, true, Encoding.Unicode);.Obuchenie(file,sw1);

///////////////////////////////////////////////

//выводим результат.Clear();(int i = 0; i < nr.neyr2; i++)

{.AppendText(Convert.ToString(Math.Round(nr.rez[i],3)) + " ");

}.Close();();

}

// ////////////////////////////////////////////////

//кнопка результатvoid button4_Click(object sender, EventArgs e)

{err = 0;file;[] znach = new bool[nr.neyr2];kl=0;(flag == false)

{.Show("Создайте сеть");;

}(int i = 0; i < nr.neyr2; i++)

{[i] = false;

}(comboBox3.Text != "")

{= comboBox3.Text;

}

{.Show("Выберите файл тестовой выборки");;

}

Рисунок А.1 - Продолжение.

Продолжение приложения А[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text(int i = 0; i < 10; i++)

{.vvod[i] = Convert.ToDouble(text[i])/10;

}

//пересчитываем результат.Rez();(int i = 0; i < nr.neyr2; i++)

{(nr.rez[i] < 0.5)[i] = false;(nr.rez[i] > 0.5)[i] = true;

}(int i = 0; i < nr.neyr2; i++)

{(znach[i] == nr.ogid1[i])

{}goto m;

}= 1;:(int i = 0; i < nr.neyr2; i++)

{(znach[i] == nr.ogid2[i])

{}goto m1;

}= 2;:.Clear();(int i = 0; i < nr.neyr2; i++)

{.AppendText(Convert.ToString(Math.Round(nr.rez[i],3)) + " ");

}(int i = 0; i < nr.neyr2; i++)

{= err + (nr.rez[i] - nr.ogid[i]) * (nr.rez[i] - nr.ogid[i]);

}= err / 2;.Clear();.AppendText(Convert.ToString(Math.Round(err,3)));(kl == 0)

{.Show("Класс не определен");

}(kl == 1)

{.Show("Выборка относится к первому классу");

}

Рисунок А.1 - Продолжение.

Продолжение приложения А(kl == 2)

{.Show("Выборка относится ко второму классу");

}

}

// ////////////////////////////////////////////////////////

// Кнопка Старт для экзаменаvoid button7_Click(object sender, EventArgs e)

{file;[] znach = new bool[nr.neyr2];kl = 0;kl_opr = 0;procent = 0;kol = 0;(flag == false)

{.Show("Создайте сеть");;

}(int i = 0; i < nr.neyr2; i++)

{[i] = false;

}(comboBox4.Text != "")

{= comboBox4.Text;

}

{.Show("Выберите файл экзаменационной выборки");;

}(file[0] == '1' || file[0] == '4')

{= 1;

}(file[0] == '2' || file[0] == '3')

{= 2;

}[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text[,] chisla = new double[text.Length / 10, 10];

//вносим в матрицу chisla данные из файла(int i = 0; i < text.Length / 10; i++)(int j = 0; j < 10; j++)

{[i, j] = Convert.ToDouble(text[10 * i + j]);

}(int qq = 0; qq < (text.Length / 10); qq++)

{

//вносим в массив vvod данные из файла(int i = 0; i < 10; i++)

{.vvod[i] = chisla[qq, i]/10;

}

//пересчитываем результат.Rez();(int i = 0; i < nr.neyr2; i++)

{(nr.rez[i] < 0.5)[i] = false;(nr.rez[i] > 0.5)[i] = true;

}(int i = 0; i < nr.neyr2; i++)

{(znach[i] == nr.ogid1[i])

{ }goto m;

}_opr = 1;:(int i = 0; i < nr.neyr2; i++)

{(znach[i] == nr.ogid2[i])

{ }goto m1;

}_opr = 2;: ;(kl == kl_opr)

{++;

}= kol / 20;= procent * 100;.Clear();.AppendText(Convert.ToString(procent));

}

}

////////////////////////////////////////

//кнопка выходvoid button8_Click(object sender, EventArgs e)

{(fl_pot)

{.Abort();.Abort();

}(sp.IsOpen)

{_connect = false;

Рисунок А.1 - Продолжение.

Продолжение приложения А.Join();.Close();

}.Exit();

}

/////////////////////////////////////////////////////

//кнопка для вывода ошибок

// ///////////////////////////////////////////////////void button9_Click(object sender, EventArgs e)

{.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;= new Thread(pot);=new Thread(pot1);_pot = true;.Start();.Start();

}

// ///////////////////////////////void pot()

{neyr1 = 15, neyr2 = 4;[] file_osibka = new string[2000];k, skor=0.7;(int i = 0; i < 2000; i++)

{_osibka[i] = "err/err" + Convert.ToString(i) + ".txt";

}

//создаем файл для вывода ошибкиii = 0;fo = new FileStream(file_osibka[ii], FileMode.Create, FileAccess.Write, FileShare.Write);.Close();sw1 = new StreamWriter(file_osibka[ii], true, Encoding.Unicode);

//for (skor = 0.1; skor < 3; skor+=0.1)

//{(k = 0.1; k < 5; k+=0.1)

{= new Neyro(neyr1, neyr2, k,skor);.Clear();.AppendText("k=" + Convert.ToString(k) + ";skor=" + Convert.ToString(skor));

//создаем сеть.CreateNS();

//обучение.Obuchenie("1-100.txt", sw1);

//sw1.Close();

//ii++;();

}

//}.Close();

//sw1.WriteLine();

//sw1.WriteLine("Время - " + dd.ToLongTimeString());

//sw1.Close();_pot = false;.Text = "Все";.Show("Поток завершен", "Все", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);

}void pot1()

{= new DateTime(1, 1, 1, 0, 0, 0);

//time = 0;(fl_pot)

}

}

// /////////////////////////////////////////////////

// Функция рисующая график

// ///////////////////////////////void grafic()

{i = 0;= this.CreateGraphics();.Clear(System.Drawing.SystemColors.Control);.Clear();.DrawLine(myPen2, 480, 250, 1000, 250);.DrawLine(myPen2, 500, 30, 500, 270);(int xx = 1; xx < 20; xx++)

{(xx, xx, 0.2, -0.2, (mx*5));

}(double yy = -2; yy <= 0; yy++)

{(0.05, -0.05, yy, yy, my);

}(i = 0; i < 99; i++)

{.DrawLine(myPen1, m_x(i), m_y(nr.err_m[i]), m_x((i) + 1), m_y(nr.err_m[i + 1]));.AppendText(Convert.ToString(i) + " " + Convert.ToString(Math.Round(nr.err_m[i],5)));.AppendText("\r\n");

Рисунок А.1 - Продолжение.

Продолжение приложения А

}.AppendText(Convert.ToString(99) + " " + Convert.ToString(Math.Round(nr.err_m[99], 5)));

}float m_x(double a)

{b;= Convert.ToInt32(a * mx + 500);b;

}float m_y(double a)

{b;= Convert.ToInt32(a * (-1) * my + 250);b;

}void delenie(double x1, double x2, double y1, double y2, int m)

{= x1 * m + 500;= x2 * m + 500;= y1 * m + 250;= y2 * m + 250;.DrawLine(myPen2, Convert.ToInt32(x1), Convert.ToInt32(y1), Convert.ToInt32(x2), Convert.ToInt32(y2));

}

//////////////////////////////////////////////////////////////////

// Кнопка соединения через ком порт Connect/Disconnect

//////////////////////////////////////////////////////////////////void button10_Click(object sender, EventArgs e)

{(!flag_connect)

{.PortName = comboBox2.Text;.BaudRate = 9600;.Parity = Parity.None;.DataBits = 8;.StopBits = StopBits.One;

// Set the read/write timeouts.ReadTimeout = 500;.WriteTimeout = 500;.Open();.Text = sp.PortName;.Clear();.Text = "Disconnect";_connect = true;= new Thread(Read);.Start();;

}(flag_connect)

{_connect = false;

Рисунок А.1 - Продолжение.

Продолжение приложения А.Join();.Close();.Text = "-";.Text = "Connect";;

}

}

//////////////////////////////////////////////////////////////////

// Поток для чтения

//////////////////////////////////////////////////////////////////void Read()

{(flag_connect)

{

{message = sp.ReadLine();.AppendText(message);

}(TimeoutException) { }

}

}

//////////////////////////////////////////////////////////////////

// Кнопка Refresh

//////////////////////////////////////////////////////////////////void button11_Click(object sender, EventArgs e)

{.Items.Clear();.Items.AddRange(SerialPort.GetPortNames());

}

//////////////////////////////////////////////////////////////////

// Кнопка Передать коэффициенты

//////////////////////////////////////////////////////////////////void button6_Click(object sender, EventArgs e)

{count_ves_k = 0; //кол-во весовых коэффициентов(flag == false)

{.Show("Создайте сеть");;

}_ves_k = 10 * nr.neyr1 + nr.neyr1 * nr.neyr2;[] mas = new string[count_ves_k];i = 0;

//Заполнение массива из матрицы w1(int q = 0; q < 10; q++)

{(int p = 0; p < nr.neyr1; p++)

{[i] = Convert.ToString(Math.Round(nr.w1[q, p],10));++;

Рисунок А.1 - Продолжение.

Продолжение приложения А

}

}

//Заполнение массива из матрицы w2(int q = 0; q < nr.neyr1; q++)

{(int p = 0; p < nr.neyr2; p++)

{[i] = Convert.ToString(Math.Round(nr.w2[q, p], 10));++;

}

}(sp.IsOpen)

{.WriteLine("w"); //для передачи коэффициентов(i = 0; i < count_ves_k; i++)

{.WriteLine(mas[i]);.Sleep(100);

}

}

{.Text = "Порт не подключен";

}

}

//////////////////////////////////////////////////////////////////

// Событие при закрытии формы

//////////////////////////////////////////////////////////////////void Form1_FormClosing(object sender, FormClosingEventArgs e)

{(flag_connect)

{_connect = false;.Join();.Close();

}

}

//////////////////////////////////////////////////////////////////

// Кнопка Sendto MC

//////////////////////////////////////////////////////////////////void button12_Click(object sender, EventArgs e)

{file;(flag == false)

{.Show("Создайте сеть");;

}

(comboBox3.Text != "")

{= comboBox3.Text;

}

{.Show("Выберите файл тестовой выборки");;

}[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text(sp.IsOpen)

{.WriteLine("c"); //для передачи чисел(int i = 0; i < 10; i++)

{.WriteLine(text[i]);.Sleep(100);

}

}

{.Text = "Порт не подключен";

}

}

}

//////////////////////////////////////////////////////////////////

// Класс, который работает с нейросетью

//////////////////////////////////////////////////////////////////class Neyro : Form1

{double[] prom, vvod;double[,] w1, w2;double[] rez;int count1=0, count2=0;int neyr1, neyr2;int[] ogid; bool[] ogid1, ogid2;double k, skor;double[] err_m = new double[100];

//конструктор. при создании объекта класса задаем параметры матрицNeyro(int neyr1, int neyr2, double k, double skor)

{.neyr1 = neyr1;.neyr2 = neyr2;.k = k;.skor = skor;.ogid = new int[neyr2];.ogid1 = new bool[neyr2];.ogid2 = new bool[neyr2];.w1 = new double[10, neyr1];.w2 = new double[neyr1, neyr2];.prom = new double[neyr1];.vvod = new double[10];.rez = new double[neyr2];number = new Random();

//Заполнение матрицы весовых коэффицентов w1(int q = 0; q < 10; q++)

{(int p = 0; p < neyr1; p++)

{[q, p] = number.NextDouble()-0.5;

}

}

//Заполнение матрицы весовых коэффицентов w2(int q = 0; q < neyr1; q++)

{(int p = 0; p < neyr2; p++)

{[q, p] = number.NextDouble()-0.5;

}

}[0] = false;(int i = 1; i < neyr2; i++)

{(ogid1[i - 1] == false)[i] = true;ogid1[i] = false;

}[0] = true;(int i = 1; i < neyr2; i++)

{(ogid2[i - 1] == false)[i] = true;ogid2[i] = false;

}

}

//код, который будет выполняться в потокеvoid Potok1(object _Data)

{sum1 = 0;(int n = 0; n < (neyr1 / 2); n++)

{(int i = 0; i < 10; i++)

{= sum1 + (vvod[i] * w1[i, n]);

}[n] = Math.Round(1 / (1 + Math.Exp((-sum1)*k)), 3);= 0;

}++;

}void Potok2(object _Data)

{sum2 = 0;(int n = (neyr1 / 2); n < neyr1; n++)

{(int i = 0; i < 10; i++)

{= sum2 + (vvod[i] * w1[i, n]);

}[n] = 1 / (1 + Math.Exp((-sum2)*k));= 0;

}++;

}void Potok3(object _Data)

{sum1 = 0;(int n = 0; n < (neyr2 / 2); n++)

{(int i = 0; i < neyr1; i++)

{= sum1 + (prom[i] * w2[i, n]);

}[n] = 1 / (1 + Math.Exp((-sum1)*k));= 0;

}++;

}void Potok4(object _Data)

{sum2 = 0;(int n = (neyr2 / 2); n < neyr2; n++)

{(int i = 0; i < neyr1; i++)

{= sum2 + (prom[i] * w2[i, n]);

}[n] = 1 / (1 + Math.Exp((-sum2)*k));= 0;

}++;

}int[] Vihod(int kol, int kl) //функция формирует ожидаемые значения

{ a=0;(kl == 2 || kl==3)= 1;[]mas=new int[kol];(int i = 0; i < kol; i++)

{[i] = a;(a == 0)= 1;a = 0;

}mas; void Korekt() //коректировка весов матриц

{[] beta2 = new double[neyr2];[] beta1 = new double[neyr1];

//double skor = 0.5;summa = 0;

//ощибка выходного слоя(int q = 0; q < neyr2; q++)

{[q] = (ogid[q] - rez[q]) * (1 - rez[q]) * rez[q];

}

//коректировка весов матрицы w2(int p = 0; p < neyr1; p++)

{(int q = 0; q < neyr2; q++)

{[p, q] = (w2[p, q] + skor * beta2[q] * prom[p]);(w2[p, q] == 0)

{[p, q] = 0.1;

}

}

}

//ошибка промежуточного слоя= 0;(int q = 0; q < neyr1; q++)

{(int k = 0; k < neyr2; k++)

{= summa + beta2[k] * w2[q, k];

}[q] = (1 - prom[q]) * prom[q] * summa;= 0;

}

//коректировка весов матрицы w1(int p = 0; p < 10; p++)

{(int q = 0; q < neyr1; q++)

{[p, q] = (w1[p, q] + skor * beta1[q] * vvod[p]);(w1[p, q] == 0)

{[p, q] = 0.1;

}

}

}

}void Rez()

{

//пересчитываем результатth_11 = new Thread(Potok1);th_22 = new Thread(Potok2);_11.Start("11");_22.Start("22");(count1 != 2) { }= 0;th_33 = new Thread(Potok3);th_44 = new Thread(Potok4);_33.Start("33");_44.Start("44");(count2 != 2) { }= 0;

}void CreateNS()

{[] text = File.ReadAllLines("1-1.txt"); //читаем содержимое файла в переменную text(int i = 0; i < 10; i++)

{[i] = Convert.ToDouble(text[i])/10; //создаем массив входных значений

}

//считаем результат();

}void Obuchenie(string file, StreamWriter sw1)

{err = 0;klass = 0;ee = 0;[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text(int qq = 0; qq < 1100; )

{= Convert.ToInt32(text[qq]);++;= Vihod(neyr2, klass); //создаем функцию которая должна получится(int i = 0; i < 10; i++)

{[i] = Convert.ToDouble(text[qq])/10;++;

}(); //пересчитываем результат(); //коректируем веса(); //еще раз пересчитываем результат

//считаем ошибку= 0;(int i = 0; i < neyr2; i++)

{= err + (rez[i] - ogid[i]) * (rez[i] - ogid[i]);

}= err / 2;_m[ee] = err; //записываем все ошибки в массив++;

//выводим ошибку.Clear();.AppendText(Convert.ToString(Math.Round(err, 5)));

//выводим ошибку в файл.Write(Convert.ToString(Math.Round(err, 5)) + " ");

}.WriteLine();

}

}

}

Рисунок А.1 - Текст программы файла Form1.cs.

Текст программы на микроконтоллер.

Текст программы файла Neyro.h представлен на рисунке Б.1.

#include "stm32f4xx.h"

#define Amount_Vvod 10 //количество входных значений

#define Neyr1 4 //количество нейронов первого слоя

#define Neyr2 2 //количество нейронов второго слоя struct

{vvod[Amount_Vvod]; //массив входных значенийprom[Neyr1]; //массив выходов первого слояrez[Neyr2];//массив выходов второго слояw1[Amount_Vvod][Neyr1];//веса нейронов первого слояw2[Neyr1][Neyr2];//веса нейронов второго слояk;//коэфициент сигмоиды skor;//коэффициент скорости обученияogid1[Neyr2];//функция ожидания для 1 классаogid2[Neyr2];//функция ожидания для 2 класса

}Neyro;Res(Neyro* nr);CreateNeyro(Neyro* nr);

Рисунок Б.1 - Текст программы файла Neyro.h.

Текст программы файла Neyro.с представлен на рисунке Б.2.

#include "Neyro.h"

#include <stdlib.h>

#include <math.h>

#include <time.h>CreateNeyro(Neyro* nr)

{i=0, j=0;

//srand(time(NULL));

//Заполнение матрицы весовых коэффициентов w1(i = 0; i < Amount_Vvod; i++)

{(j = 0; j < Neyr1; j++)

{>w1[i][j] = (double)(rand()%3)-0.5;

}

}

//Заполнение матрицы весовых коэффициентов w2(i = 0; i < Neyr1; i++)

{(j = 0; j < Neyr2; j++)

{>w2[i][j] = (double)(rand()%3)-0.5;

}

} >ogid1[0] = 0;(i = 1; i < Neyr2; i++)

{(nr->ogid1[i - 1] == 0)>ogid1[i] = 1;nr->ogid1[i] = 0;

}>ogid2[0] = 1;(i = 1; i < Neyr2; i++)

{(nr->ogid2[i - 1] == 0)>ogid2[i] = 1;nr->ogid2[i] = 0;

}

}Res(Neyro* nr)

{sum = 0;n=0,i=0;(n = 0; n < Neyr1; n++)

{(i = 0; i < Amount_Vvod; i++)

{= sum + (nr->vvod[i] * nr->w1[i][n]);

}>prom[n] = 1 / (1 + exp((-sum)*nr->k));=0;

}=0;(n = 0; n < Neyr2; n++)

{(i = 0; i < Neyr1; i++)

{= sum + (nr->prom[i] * nr->w2[i][n]);

}>rez[n] = 1 / (1 + exp((-sum)*nr->k));=0;

}

}

Текст программы файла main.с представлен на рисунке Б.3.

#include "stm32f4xx.h"

#include "stm32f4_discovery.h"

#include "Neyro.h"

#include <stdlib.h>

#define NOM 15//количество принимаемых байт через UARTbufer[NOM];//буфер для приема через COMchar flag_uart=0;//флаг для уарт, если 1 то принята инфаuint64_t timeout=0;//таймаут для уартint count_bufer=0;//счетчик элементов буфера уартint flag_koef=0;//когда =1 принимаем коэффициенты матрицint flag_chisla=0;//когда =1 принимаем числаbuf_koef[(10*Neyr1)+(Neyr1*Neyr2)]; //преобразованные коэффициентыbuf_chisla[Amount_Vvod];  //преобразованные числаnr;int delay_time=0;//переменная для задержки

//////////////////////////////////////////////////////////////////////////

//задержка в милисекундах, работает через таймер SysTickdelay(int n)

{_time=n;(delay_time != 0);

}

/////////////////////////////////////////////////////////////////////.....

// Инициализация УАРТа

//////////////////////////////////////////////////////////////////////////InitUart4(void)

{_InitTypeDef GPIO_uart;_InitTypeDef USART_InitStructure;

//USART_ClockInitTypeDef USART_ClockInitStructure;

//enable bus clocks_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

//Set UART4 Tx (PC.10) as AF push-pull_uart.GPIO_Pin = GPIO_Pin_10;_uart.GPIO_Mode = GPIO_Mode_AF;_uart.GPIO_OType = GPIO_OType_PP;_uart.GPIO_Speed = GPIO_Speed_50MHz;_Init(GPIOC, &GPIO_uart);

//Set UART4 Rx (PC.11) as input floating_uart.GPIO_Pin = GPIO_Pin_11;_uart.GPIO_Mode = GPIO_Mode_AF;_uart.GPIO_OType = GPIO_OType_PP;_uart.GPIO_PuPd = GPIO_PuPd_UP;_uart.GPIO_Speed = GPIO_Speed_50MHz;_Init(GPIOC, &GPIO_uart);_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);

//USART_ClockStructInit(&USART_ClockInitStructure);

//USART_ClockInit(UART4, &USART_ClockInitStructure);_InitStructure.USART_BaudRate = 9600;_InitStructure.USART_WordLength = USART_WordLength_8b;_InitStructure.USART_StopBits = USART_StopBits_1;_InitStructure.USART_Parity = USART_Parity_No ;_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

//Write UART4 parameters_Init(UART4, &USART_InitStructure);

//разрешение прерывания по приему данных_ITConfig(UART4, USART_IT_RXNE, ENABLE);_EnableIRQ(UART4_IRQn); //вкл прерывание

//USART_ITConfig(UART4, USART_IT_TXE, DISABLE);

//Enable USART4_Cmd(UART4, ENABLE);

}

//////////////////////////////////////////////////////////////////////

// Инициализация портов

//////////////////////////////////////////////////////////////////////////InitPorts()

{_InitTypeDef gpiod;_InitTypeDef gpioa;

//тактирование порта D, A_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

//настройка порта D на выход .GPIO_Mode = GPIO_Mode_OUT;.GPIO_OType = GPIO_OType_PP;.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;.GPIO_Speed = GPIO_Speed_50MHz;

// Инициализируем GPIO на порту D

//GPIO_DeInit(GPIOD);_Init(GPIOD, &gpiod);

//настройка порта А на вход, используется кнопка подключенная к земле и к контроллеру.GPIO_Mode = GPIO_Mode_IN;.GPIO_OType = GPIO_OType_PP;.GPIO_Pin = GPIO_Pin_0;.GPIO_Speed = GPIO_Speed_50MHz;

// Инициализируем GPIO на порту A

//GPIO_DeInit(GPIOA);_Init(GPIOA, &gpioa);

}

///////////////////////////////////////////////////////////////////////////

// Прерывание УАРТа

//////////////////////////////////////////////////////////////////////////UART4_IRQHandler()

{=0;(flag_uart==1)

{;//если буфер не обработан, то выходим

}

//записываем принятое значение в буфер[count_bufer] = USART_ReceiveData(UART4);

// если приняли w, значит идете передача весовых коэф-ов(bufer[count_bufer] == 'w')

{_koef=1;;

}

// если приняли c, значит идете передача чисел на распознавание(bufer[count_bufer] == 'c')

{_chisla=1;;

}(bufer[count_bufer] == ',')

{[count_bufer] = '.';

}

//максимум NOM байт, если счетчик равен NOM, значит приняли все полностью_bufer++;(count_bufer==NOM)

{_bufer=0;_uart=1;

}

}

//////////////////////////////////////////////////////////////////////////

// Обработчик прерывания по переполнению таймера SysTick

//////////////////////////////////////////////////////////////////////////SysTick_Handler()

{int i=0;srav=500;++;(flag_koef==1 || flag_chisla==1)

{=100;(i>100)

{=0;

}

}(flag_koef==0 && flag_chisla==0)

{=500;

}(i==srav)

{

// Мигание светодиодом _ToggleBits(GPIOD, GPIO_Pin_15);=0;

}

//если задана задержка delay(delay_time != 0)

{_time--;

}

//если что то приняли, ждем таймаут(count_bufer != 0)

{++;

//если таймаут вышел, значит больше ничего не придет(timeout>30)

{_bufer=0;_uart=1;=0;

}

}

}

//////////////////////////////////////////////////////////////////////////InitNeyro()

{.k=1.3;.skor=0.7;(&nr);

}

//////////////////////////////////////////////////////////////////////////

// Функция записы коэффициентов в матрицы

//////////////////////////////////////////////////////////////////////////Write_koef(Neyro* nr, const double *buf)

{i,j;

//Заполнение матрицы весовых коэффициентов w1(i = 0; i < Amount_Vvod; i++)

{(j = 0; j < Neyr1; j++)

{>w1[i][j] = *buf++;

}

}

//Заполнение матрицы весовых коэффициентов w2(i = 0; i < Neyr1; i++)

{(j = 0; j < Neyr2; j++)

{>w2[i][j] = *buf++;

}

}

}

//////////////////////////////////////////////////////////////////////////

// Функция записы коэффициентов в матрицы

//////////////////////////////////////////////////////////////////////////Write_vvod(Neyro* nr, const double *buf)

{i;

//заполнение массива входных значений (i = 0; i < Amount_Vvod; i++)

{>vvod[i]=*buf/10;++;

}

}Klass(Neyro* nr)

{i;znach[Neyr2];kl=0;(i = 0; i < Neyr2; i++)

{(nr->rez[i] < 0.5)

{[i] = 0;

}(nr->rez[i] > 0.5)

{[i] = 1;

}

}(i = 0; i < Neyr2; i++)

{(znach[i] == nr->ogid1[i])

{}goto m;

}= 1;:(i = 0; i < Neyr2; i++)

{}goto m1;

}= 2;:(kl == 0)

{

//вкл-выкл светодиодами_SetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);(100);_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);

}(kl == 1)

{_SetBits(GPIOD, GPIO_Pin_12);

}(kl == 2)

{_SetBits(GPIOD, GPIO_Pin_14);

}

}

//////////////////////////////////////////////////////////////////////////main(void)

{i=0;cnt=0;=sizeof(double);();();();

// Конфигурируем таймер SysTick на срабатывание 1000 раз в секунду _Config(SystemCoreClock / 1000);(1)

{

//если приняты данные через уарт(flag_uart==1)

{

//если принимаем коэффициенты(flag_koef==1)

{_koef[cnt]=atof(bufer);++;

//если приняли все коэффициенты(cnt == (10*Neyr1)+(Neyr1*Neyr2) )

{=0;_koef=0;

//записываем в матрицы_koef(&nr,&buf_koef[0]);

//вкл-выкл светодиодами_SetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);(200);_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);

}

}

//если принимаем числа(flag_chisla==1)

{_chisla[cnt]=atof(bufer);++;

//если приняли все числа(cnt==Amount_Vvod)

{=0;_chisla=0;_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);(200);

//записываем в массив входных значений_vvod(&nr,&buf_chisla[0]);(&nr);(&nr);

}

}

//обнуление буфера(i=0;i<NOM;i++)

{[i]=0;

}_uart=0;//снимаем флаг уарта

}

}

}

Рисунок Б.3

Похожие работы на - Разработка и исследование модели нейросетевого регулятора на микроконтроллере STM32F407VG

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!