Управление текстовыми командами (usart на stm32)

STM32 с нуля. USART. Пример программы

Продолжаем нашу рубрику STM32 с нуля, диодиком помигали, таймером поиграли, пора наладить связь с внешним миром ) Для этого сегодня будем разбираться как работает в микроконтроллерах STM32 USART. И, собственно, напишем для USART пример программы.

Что такое USART и зачем он нужен думаю объяснять не надо ) Так что перейдем сразу к реализации протокола в STM32. Предлагаю сначала посмотреть какие там регистры за что отвечают, а потом уже набросать какой-нибудь проектик для наглядности.

Небольшое лирическое отступление ) Как вы уже догадываетесь модуль USART STM32, как и все остальное в этих микроконтроллерах, имеет множество настроек и режимов.

Тут тебе и обычный прием/передача и поддержка LIN (об этом протоколе как-нибудь поговорим отдельно).

И если в AVR частенько приходилось мутить софтовые UART’ы, поскольку аппаратных просто не хватало, то в STM32F103CB их как минимум три штуки! А это уже немало. Итак, начинаем копаться в даташите.

Регистр USART_SR.
Статусный регистр. Тут содержатся флаги, отражающие текущее состояние дел, то есть текущее состояние модуля USART. Поглядим на некоторые флаги поближе:

LBD – Lin Break Detection flag.
Выставляется при обнаружении брейка при использовании LIN (о том, что это такое обязательно расскажу в статье про LIN)

TXE – Transmit data register empty
Регистр данных пуст, пора его заполнить!

TC – Transmission complete
Передача завершена

RXNE – Read data register not empty Приемный регистр не пуст, надо срочно читать!

Есть там еще 4 флага для классификации ошибок – ошибка кадра, наличие шума, ошибка переполнения.

Регистр USART_DR. Регистр данных.

Именно тут мы будем забирать ценнейшую информацию, которая к нам пришла извне, а также будем сюда сливать свою информацию.

Регистр USART_BRR.
Сюда записывается скорость обмена, которую мы хотим получить.

Регистр USART_CR1.
Регистр контроля – контролирует весь процесс. Биты по порядку:

UE – Разрешение работы USART

M – Длина посылки: 0 – 8 бит данных, 1 – 9 бит данных

Wake – Будильник для USART’a – то есть метод его пробуждения

PCE – Контроль паритета – ВКЛ или ВЫКЛ

PS – Тип паритета: 0 – четный, 1 – нечетный

PEIE – Разрешение прерывания при обнаружении ошибки паритета

TXEIE – Прерывание от TXE

RXNEIE – Прерывание от RXNE
Ну и там еще парочка битов, разрешающих/запрещающих прием/передачу, а также бит для отправки брейка. В общем, это все есть в даташите, все наглядно, красиво и понятно ) Тут просто на всякий случай это пишу.

Регистр USART_CR2.
Тут у нас спрятались такие биты как, включение/выключение режима работы по LIN, установка количества стоп-бит, настройки clock’а, установка параметров LIN брейка и некоторые другие.

Регистр USART_CR3.
А здесь биты для использования DMA и SmartCard.

Регистр USART_GTPR.
А в нем находятся биты, отвечающие за предделитель.

В общем, вот они, 7 регистров, которые контролируют весь модуль USART в STM32. У меня описаны довольно поверхностно, только основное, если что, спрашивайте )

Собственно, пришло время немного попрограммировать. Пусть в нашем USART примере программка опрашивает кнопку, и если ее кто-нибудь ткнет, то контроллер вышлет в USART сообщение «Pressed», а если кнопка так и будет скучать не нажатой, то во внешний мир полетит «Not Pressed».

Итак, как же мы будем это реализовывать? А очень просто (вот на всякий случай статья про создание нового проекта). Создадим функцию, которая будет опрашивать кнопку и записывать в буфер соответствующее сообщение. Кроме того, она будет в специальную переменную записывать количество байт, которые надо передать.

В прерывании мы будем совать очередной байт в USART и увеличивать счетчик переданных байт. Когда значение счетчика станет равно количеству байт, которые необходимо передать (это означает, что все сообщение передано), снова будем вызывать функцию-опросчик кнопки. И так бесконечно. Перейдем к реализации алгоритма (не забываем добавить в проект файлы stm32f10x_usart.h и stm32f10x_usart.

c из Standard Peripheral Library). Ниже приведен полный код примера с пояснениями:

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}
/****************************usart.c*********************************/
#include “stm32f10x.h”
#include “stm32f10x_rcc.h”
#include “stm32f10x_gpio.h”
#include “stm32f10x_tim.h”
#include “stm32f10x_usart.h”
 
/*******************************************************************/
#define BAUDRATE 9600
 
/*******************************************************************/
GPIO_InitTypeDef port;
USART_InitTypeDef usart;
//Переменная для хранения передаваемых данных
uint8_t usartData[10];
uint16_t button;
//Счетчик переданных байт
uint16_t usartCounter = 0;
//А тут будет количество байт, которые нужно передать
uint16_t numOfBytes;
 
/*******************************************************************/
void initAll()
{ //Включаем тактирование RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  //Пины PA9 и PA10 в режиме альтернативных функций – //Rx и Tx USART’а GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port);
  port.GPIO_Mode = GPIO_Mode_IN_FLOATING; port.GPIO_Pin = GPIO_Pin_10; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port);
  //Настройка USART, все поля оставляем дефолтными, кроме скорости обмена USART_StructInit(&usart); usart.USART_BaudRate = BAUDRATE; USART_Init(USART1, &usart);
  //Здесь будет висеть наша кнопка port.GPIO_Mode = GPIO_Mode_IPD; port.GPIO_Pin = GPIO_Pin_2; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &port);
}
 
/*******************************************************************/
//Вот она, функция-опросчик кнопки
void setData()
{ button = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2); if (button == 0) { usartData[0] = 'N'; usartData[1] = 'o'; usartData[2] = 't'; usartData[3] = 'P'; usartData[4] = 'r'; usartData[5] = 'e'; usartData[6] = 's'; usartData[7] = 's'; usartData[8] = 'e'; usartData[9] = 'd'; numOfBytes = 10; } else { usartData[0] = 'P'; usartData[1] = 'r'; usartData[2] = 'e'; usartData[3] = 's'; usartData[4] = 's'; usartData[5] = 'e'; usartData[6] = 'd'; numOfBytes = 7; } usartCounter = 0;
}
 
/*******************************************************************/
int main()
{ __enable_irq (); initAll(); //Включаем прерывания по приему байта и по окончанию передачи USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_TC, ENABLE); //Запускаем сам USART USART_Cmd(USART1, ENABLE); //Первая установка сообщения, вне цикла setData(); NVIC_EnableIRQ(USART1_IRQn); while(1) { //Собственно вот он весь описанный ранее алгоритм if (usartCounter >= numOfBytes) { setData(); } }
}
 
/*******************************************************************/
//А в прерывании выдаем байт и увеличиваем счетчик
void USART1_IRQHandler()
{ if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) { if (usartCounter Serial Windows и выбираем наш USART – то есть USART номер один. В правом нижнем углу появится окошко, в котором будем видеть все сообщения, которые выдает USART. Запускаем программу и эмулируем нажатие кнопки, выставляя нужный бит в окне GPIOB. И вот что получилось:Согласен, не слишком наглядно и красиво, но то, что программа работает как мы и задумали, не вызывает ни малейших сомнений ) С передачей все прошло гладко, давайте попробуем что-нибудь принять. Итак, реализуем еще один пример.Пусть будет такая задача – в зависимости от принятого байта зажигать один из двух диодов. То есть приняли «1» – зажгли первый, приняли «2» – зажгли второй. Тут мы снова прибегнем к языку сценариев (об этом писалось в одной из предыдущих статей – вот в этой) для эмуляции приему сообщения по USART. Создаем файл usart.ini и заполняем его следующим кодом:

/*******************************************************************/
func void usart1()
{ S1IN = '1';
}
/*******************************************************************/
func void usart2()
{ S1IN = '2';
}
/*******************************************************************/

Кода немного, но достаточно для нашей цели =) S1IN – вход для эмуляции входа последовательного порта. Таким образом, вызвав в командной строке функцию usart1() получим на вход USART’a – «1», а вызвав usart2() – получим «2».

Теперь код основной программы:

/****************************usart1.c*********************************/
#include “stm32f10x.h”
#include “stm32f10x_rcc.h”
#include “stm32f10x_gpio.h”
#include “stm32f10x_usart.h”
 
/*******************************************************************/
#define BAUDRATE 9600
 
/*******************************************************************/
GPIO_InitTypeDef port;
USART_InitTypeDef usart;
uint8_t usartData;
 
/*******************************************************************/
void initAll()
{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port);
  port.GPIO_Mode = GPIO_Mode_IN_FLOATING; port.GPIO_Pin = GPIO_Pin_10; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port);
  USART_StructInit(&usart); usart.USART_BaudRate = BAUDRATE; USART_Init(USART1, &usart);
  port.GPIO_Mode = GPIO_Mode_Out_PP; port.GPIO_Pin = GPIO_Pin_1; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &port);
  port.GPIO_Mode = GPIO_Mode_Out_PP; port.GPIO_Pin = GPIO_Pin_2; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &port);
}
 
//Пока все как обычно, ничего нового
 
/*******************************************************************/
int main()
{ __enable_irq (); initAll(); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); NVIC_EnableIRQ(USART1_IRQn); while(1) { //Если приняли «1» зажигаем диод 1 и гасим диод 2, //приняли «2» – все наоборот if (usartData == '1') { GPIO_SetBits(GPIOB, GPIO_Pin_1); GPIO_ResetBits(GPIOB, GPIO_Pin_2); } if (usartData == '2') { GPIO_SetBits(GPIOB, GPIO_Pin_2); GPIO_ResetBits(GPIOB, GPIO_Pin_1); } }
}
 
/*******************************************************************/
void USART1_IRQHandler()
{ //Проверяем, действительно ли прерывание вызвано приемом нового байта if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { usartData = USART_ReceiveData(USART1); }
}
 
/****************************End of file****************************/

Опять все очень несложно, даже комментировать толком не пришлось )

Запускаем отладчик Keil, настраиваем логический анализатор на порты PB1 и PB2, подключаем наш файл .ini (написав в командной строке include usart.ini) и поочередно вызываем функции usart1() и usart2(). Вот что из этого безобразия вышло:

(Тыкайте на картинку для увеличения, а то так ничего толком не видно)

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

Диоды мигают так как надо )

Итак, мы разобрались с работой USART, с приемом и передачей, следите за развитием событий в следующих статьях )

Источник: https://microtechnics.ru/stm32-uchebnyj-kurs-usart/

ვიდეოს გადმოწერა, უყურეთ უფასოდ

2:19:55

Eşkıya Dünyaya Hükümdar Olmaz 108. Bölüm

ნახვები 502 938 89%

10:15

7 Funny and Useful Beauty Hacks

ნახვები 10 997 315 84%

4:14

KILLSHOT [Official Audio]

ნახვები 115 516 515 97%

3:3:07

Sen Anlat Karadeniz 22. Bölüm

ნახვები 3 866 366 94%

2:28:02

ნახვები 4 845 889 94%

49:46

Комеди Клаб, 14 сезон, 30 выпуск

ნახვები 131 154 89%

5:35

ნახვები 27 853 96%

6:04

ჩხუბები და გარჩევები | ნაწილი 2

ნახვები 40 405 97%

1:00

Ранняя Пташка 13 серия 2 фраг русские субтитры.

ნახვები 31 413 98%

2:05

ნახვები 60 602 99%

17:47

ლეგენდარული ფინტები ჩვენი შესრულებით

ნახვები 25 284 99%

1:57

Marvel Studios' Captain Marvel – Official Trailer

ნახვები 38 556 153 93%

11:28

ГДЕ РОЗЫ ПРОСТОЯТ ДОЛЬШЕ? – КОЛА, ВОДКА ИЛИ ВОДА?

ნახვები 4 591 027 96%

2:13:34

World Judo Championships 2018: Day 7 – Elimination

ნახვები 49 380 94%

10:50

Сквиши против реальной еды! Челлендж – 8 идей

ნახვები 1 376 567 92%

2:14:02

ნახვები 919 674 92%

3:19

Lil Peep & XXXTENTACION – Falling Down

ნახვები 25 029 988 98%

3:57

როგორ გადავრჩეთ ექსტრემალურ პირობებში ?

ნახვები 35 658 99%

2:58

ნახვები 414 561 98%

9:25

Самый дорогой IPhone | провал Apple?

ნახვები 508 529 95%

15:43

მამაოს ჯიგრული გამოსვლა კომიტეტის სხდომაზე

ნახვები 61 806 87%

7:33

Archery Trick Shots 2 | Dude Perfect

ნახვები 6 457 194 99%

12:51

Кавказец офигел от ботаника!

ნახვები 5 780 071 95%

5:49

Eminem – Lucky You ft. Joyner Lucas

ნახვები 41 696 608 98%

10:29

World's Strongest Hands ✅

ნახვები 20 092 833 85%

48:55

ნახვები 382 940 54%

2:33:37

ნახვები 1 269 796 92%

6:52

E73 Baked Cement Charcoal Oven Mooncake | Ms Yeah

ნახვები 3 217 650 96%

12:15

КАТАЕМСЯ В HEELYSах ПО ШКОЛЕ!!!ВСЕ НАКАЗАНЫ!!!

ნახვები 2 665 341 83%

15:34

Самодельный Ламборгини. Последние доработки!

ნახვები 1 122 401 94%

13:08

Что если затопить блютус колонку?

ნახვები 651 349 82%

5:26

ШКУРА ПОВЕЛАСЬ НА ФЕРРАРИ ИТАЛИЯ И БРОСИЛА ПАРНЯ

ნახვები 3 231 111 94%

1:31:12

Замуж за Бузову – 1 сезон, 5 выпуск

ნახვები 115 644 81%

4:31

Менять власть Путина #СергейУдальцов

ნახვები 43 050 24%

12:05

Sweetie Bean | Funny Clips | Mr Bean Official

ნახვები 8 981 628 86%

12:00

Что делать, когда скучно – 12 идей!

ნახვები 862 658 85%

14:43

ნახვები 5 032 024 96%

2:29

ЧТО, ЕСЛИ ты можешь БЫТЬ ЛЮБОГО РАЗМЕРА

ნახვები 973 492 94%

48:48

Юлия Латынина – Код доступа… 22.09.18

ნახვები 43 215 11%

23:59

EN RAHATLATICI YEMEK VİDEOLARI (Tepki)

ნახვები 1 750 566 83%

0:51

ნახვები 1 382 883 97%

Источник: https://gevid.net/video/%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%BC%D0%B8-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0%D0%BC%D0%B8-usart-%D0%BD%D0%B0-stm32-Qf4isR04F6s.html

بهترین فیلم ها

404

Will Smith Bungee Jumps Out of a Helicopter!

  • Will Smith
  • بازدید 8 975 805

Ultimate MRE Taste Test

  • Good Mythical Morning
  • بازدید 400 619

Hasan Minhaj's Groupon Proposal Fail

  • Jimmy Kimmel Live
  • بازدید 397 794

Archery Trick Shots 2 | Dude Perfect

  • Dude Perfect
  • بازدید 6 446 928

Why colleges tolerate fraternities

$10 QUEER EYE TRANSFORMATION (w/ Jon Cozart)

$1 Cookie Vs. $90 Cookie

  • BuzzFeedVideo
  • بازدید 4 032 012

DIY 7 INGREDIENT SANDWICH STADIUM

Источник: https://ir-film.com/v-%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%BC%D0%B8-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0%D0%BC%D0%B8-usart-%D0%BD%D0%B0-stm32-Qf4isR04F6s.html

UART в STM32. Часть 1

Благодаря предыдущей статье, у нас теперь есть базовые представления об интерефейсе UART. Руководствоясь ими и даташитом на контроллер STM32F100RBT6B попробуем разобраться, как что-то передать через UART в компьютер и наоборот, заставить контроллер принять что-то от компьютера.

Начать нужно с того, что UART интерфейс в контроллерах STM32 не один, в вышеупомянутом контроллере их аж три штуки. Я планирую использовать UART1, следовательно передающий провод (TxD) от USB-UART преобразователя я подсоединяю к ноге контроллера работющей на приём (PA10), а передающую ногу (PA9) я подключаю ко входу (RxD) преобразователя USB-UART.

Для работы с этим интерфейсом существует великое множество регистров. Для облегчения работы программиста, вместе с CooCox'ом поставлятся библиотека предназначеная для работы с UART'ом. Я довольно хорошо изучил её и она мне понравилась, но для лучшего понимания принципов её работы нужно вкратце познакомится с регистрами.

В следующей статье, в которой будет описан практический пример использования UART'a, я буду использовать именно её. Для начала стоит сказать что нужно настроить чтоб интерфейс заработал:  

  1. Включить тактирование порта А
  2. Настроить ногу PA9 как выход push-pull в альтернативном режиме. Частота 50 МГц
  3. Настроить ногу PA10 как вход без подтяжки
  4. Включить тактирование UART1
  5. Настроить параметры UART1: Скорость, кол-во стоп бит, проверку четности итд.

С первыми четырьмя пунктами проблем быть не должно, всё это знакомо из статьи про порты микроконтроллера, а вот с пятым пунктом немного сложнее, но попробуем разобраться. 

Начнем с регистра USART_BRR при помощи которого задаётся скорость приёма/передачи: 

Регистр делится на две части: Целая (DIV_Mantissa) и дробная (DIV_Fraction). Для получения значения которое нужно записать в этот регистр, нужно воспользоваться формулой:

USART_BRR = (fck + baudrate /2 ) / baudrate

где fck это частота тактирования UART1, а baudrate это желаемая скорость передачи/приёма. Со скоростью всё понятно, а как определить fck ? Забегая вперед, скажу, что это отдельная тема для большой статьи (которая будет).

Эта частота будет равна 24 Мгц если использовать кварц на 8 МГц и ничего не менять в настройках тактирования, а оставить их по умолчанию. Приведу пример рассчётов: Я хочу настроить уарт на скорость 9600. Путем нехитрых рассчётов получаем (24000000 + 9600 / 2)/ 9600 = 2500.

5 потом отсекаем дробную часть, переводим число в шестнадцатеричную систему счисления и получаем 0x9c4. Еще есть другая формула, руководствуясь которой можно вычислить значение регистра USART_BRR.

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

fck / (16*baudrate)

Дробную часть нужно округлить до сотых и умножить на 16. Потом еще раз округлить но уже до целого. После этого записать её в биты DIV_Fraction. Попробуем рассчитать регистр USART_BRR но уже с использованием этого способа. 24000000 / (16 * 9600) = 156,25.

Целая часть 156 – пойдет в DIV_Mantissa без изменений, а дробную часть 0.25 умножаем на 16 и получаем 4. Округлять тут нам не пришлось, поэтому в DIV_Fraction записываем 4. Переведем 156 и 4 в шестнадцатиричную систему счисления и получим 0x9c и 0x04 а вместе они образуют 0x9c4. В итоге мы получили тот же самый результат.

Но лично мне первый способ больше по душе 🙂 Следующий регистр USART_CR1:  

UE – Бит предназначен для включения UART'a. То есть просто подать тактирование мало, чтоб уарт заработал надо установить этот бит в единицу. 

M – задает количество бит даннных которое будет передаваться за раз. Если бит равен 0, тогда уарт будет отправлять/принимать по 8 бит, если единице то 9 бит. Почему бит называется М для меня так и осталдось загадкой.

PCE – Если бит равен 1 то контроль чётности включен, в противном случае выключен.
PS – тип контроля чётности: 0 – чёт, 1 – нечет.
TE – Если бит равен 1 то разрешена работа передатчика (нога TxD)
RE – Если бит равен 1 то разрешена работа приёмника (нога RxD)

Как видно по двум последним битам в этой таблице – передатчик и приёмник друг от друга не зависят. Если не требуется принимать(или передавать) данные, то можно сэкономить одну ножку контроллера (TxD или RxD) просто не включая не нужную нам часть UART'a.

Следующий регистр настроек это USART_CR2

В нем нас интересуют только два бита: STOP1, STOP0

При помощи этих двух бит можно задать количество стоповых бит в посылке.

STOP1   STOP0   Количество стоповых бит
1 стоп бит
1 0.5 стоп бита
1 2 стоп бита
1 1 1.5 стоп бита

Конечно я описал далеко не все биты, но все нам и не понадобятся, во всяком случае пока. Чтобы произвести минимальную настройку будет достаточно знать то что я написал выше. После того как всё настройки уарта произведены можно попробовать что-то отправить/получить через UART. Для приёма/передачи служит регистр USART_DR:

В нем используются первые 8 или 9 бит (в зависимости от бита M в регистре USART_CR1). Чтоб отправить в UART данные просто записываем их в этот регистр. Чтоб прочитать данные просто читаем этот регистр. С этим ни каких сложностей, но не понятно когда мы можем читать и передавать данные.

Ведь отправлять данные очень быстро нельзя, так как уарт может быть настроен на очень маленькую скорость передачи. И пытаясь начать новую передачу данных в то время как предыдущая передача не завершена не имеет особого смысла. С приёмом данных похожая ситуация. Бессмысленно читать регистр данных (USART_DR) если в него ничего не пришло.

Для отслеживания состояния в котором находится UART, служит регистр USART_SR.

RXNE – Этот бит устанавливается когда в UART что-то пришло. Если не забрать из USART_DR, данные то они перезатрутся новыми если таковые будут.

TC – Если этот бит установлен в единицу, то это означает что передача данных завершена и можно опять что-то записывать в регистр данных (USART_DR). Остальные биты нам пока не потребуются.

Ну все, довольно табличек и теории. Попробуем передать в комп строку с приветствием и смайликом. 

#include “stm32f10x.h”
#include “stm32f10x_gpio.h”
#include “stm32f10x_rcc.h” //Функция предназначена для формирования небольшой задержки
void Delay(void) { volatile uint32_t i; for (i=0; i != 0x70000; i++);
} //Функция отправляющая байт в UART
void send_to_uart(uint8_t data) { while(!(USART1->SR & USART_SR_TC)); //Ждем пока бит TC в регистре SR станет 1 USART1->DR=data; //Отсылаем байт через UART
} int main(void) { GPIO_InitTypeDef PORTA_init_struct; // Включаем тактирование порта А и USART1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); // Настраиваем ногу TxD (PA9) как выход push-pull c альтернативной функцией PORTA_init_struct.GPIO_Pin = GPIO_Pin_9; PORTA_init_struct.GPIO_Speed = GPIO_Speed_50MHz; PORTA_init_struct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &PORTA_init_struct); //Настраиваем UART USART1->BRR=0x9c4; //BaudRate 9600 USART1->CR1 |= USART_CR1_UE; //Разрешаем работу USART1 USART1->CR1 |= USART_CR1_TE; //Включаем передатчик //Все остальные параметры (стоп биты, чётность,кол-во байт данных) уже настроены //как надо, (во все эти биты по умолчанию записаны нули), таким образом мы имеем // скорость 9600 1 стоп бит, 8 бит данных, без проверки чётности while(1) { //Выдаем в UART слово Hello send_to_uart('H'); send_to_uart('e'); send_to_uart('l'); send_to_uart('l'); send_to_uart('o'); send_to_uart(' '); send_to_uart(':'); send_to_uart(')'); send_to_uart('
'); Delay(); //небольшая задержка }
}

Создаем пустой проект в CooCox'е, копируем код, компилируем и прошиваем. Я тестировал этот код на платке STM32VL Discovery с кварцем 8 МГц. На ногу PA9 я подключил вход (RxD) моего USB-UART преобразователя, настроил терминальную программу на скорость 9600 бит/сек, 1 стоп бит, без проверки чётности.  В результате получил следующую картинку: 

В следующей статье мы попробуем сделать с использованием UART'a нечто более полезное с практической точки зрения.

Источник: http://easystm32.ru/15/

USART в stm32

Когда речь заходит об интерфейсах передачи данных, USART (в народе S часто упускают) – самая нужная штуковина. Благодаря ему разработчики имеют возможность организовать передачу данных по интерфейсам RS-232, RS-485 и даже 1-Wire.

USART (Universal Synchronous/Asynchronous Receiver/Transmitter) – универсальный синхронный/асинхронный (вот тут и зарыт секрет буквы S) приемопередатчик.

Как может пригодиться USART начинающему радиолюбителю?

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

Если же у вас нет COM порта можете воспользоваться переходником на основе микросхемы ft232.
Все проще чем разбираться с километровыми спецификациями USB. Конечно их знание весомый плюс, но новичку в них разобраться ох как сложно.

Использование USART в stm32

В контроллерах stm32 модулей USART целая туча. Вы можете пользоваться любым. Я покажу на примере USART1.
Весь код будет построен на основе библиотеки от ST.

Для работы подключаем такие модули библиотеки:

#include “stm32f4xx.h”
#include “stm32f4xx_gpio.h”
#include “stm32f4xx_rcc.h”
#include “stm32f4xx_usart.h”

Объявим две структуры для хранения настроек периферии.

//Структуры для инициализации GPIOA и USART1
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;

Прототипы функций:

void Usart1_Init(void); //Объявление функции инициализации периферии
void Usart1_Send_symbol(uint8_t); //Объявление функции передачи символа
void Usart1_Send_String(char* str); //Объявление функции передачи строки

Функция инициализации USART1:

void Usart1_Init() { //Включаем тактирование GPIOA, USART1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //Инициализация вывода PA9 – USART1_Tx GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //Настройки вывода PA9 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // скорость порта GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // режим альтернативной функции GPIO_Init(GPIOA, &GPIO_InitStruct); // заданные настройки сохраняем в регистрах GPIOА //Инициализация вывода PA10 – USART1_Rx GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; // настройки вывода PA10 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // режим альтернативной функции GPIO_Init(GPIOA, &GPIO_InitStruct); // заданные настройки сохраняем в регистрах GPIOА GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //Инициализация USART1 USART_InitStruct.USART_BaudRate = 1200; // скорость обмена 1200 бод USART_InitStruct.USART_WordLength = USART_WordLength_8b; // длина слова 8 бит USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1 стоп-бит USART_InitStruct.USART_Parity = USART_Parity_No ; // без проверки четности USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // без аппаратного контроля USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // включен передатчик и приемник USART1 USART_Init(USART1, &USART_InitStruct); // заданные настройки сохраняем в регистрах USART1 USART_Cmd(USART1, ENABLE); // включаем USART1
}

Функция передачи байта через USART:

void Usart1_Send_symbol(uint8_t data) { while(!(USART1->SR & USART_SR_TC)); // проверяем установку флага TC – завершения предыдущей передачи USART1->DR = data; // записываем значение в регистр данных – передаем символ
}

Фунция передачи строки через USART:

void Usart1_Send_String(char* str) { uint8_t i=0; while(str[i]) { Usart1_Send_symbol(str[i]); i++; } // передаем сивол конца строки Usart1_Send_symbol('
'); Usart1_Send_symbol('
');
}

Для использования необходимо провести инициализацию соответствующей функцией и отправить нужные байты.

int main() { Usart1_Init(); //Вызов функции инициализации периферии //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными Usart1_Send_String(“I'm ready!”); while(1) { }
}

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

На практике считается нормальной скорость в 9600 бод. Но я “на коленке” не сумел получить стабильную передачу на скорости выше 2400.

Источник: http://blablacode.ru/mikrokontrollery/434

STM32F103VCT6: Программирование USART

Согласно даташиту, микроконтроллеры STM32F103xC, STM32F103xD и STM32F103xE содержат 5 каналов USART. Конкретно у STM32F103VCT6 эти каналы выведены на пины:

Канал Пин Примечание
USART1 RX: PA10 / TX: PA9CK: PA8 / CTS: PA11 / RTS: PA12 до 4.5 Мбит/с (APB2)
USART2 RX: PA3 / TX: PA2CK: PA4 / CTS: PA0 / RTS: PA1 до 2.25 Мбит/с (APB1)
USART3 RX: PB11 / TX: PB10CK: PB12 / CTS: PB13 / RTS: PB14 до 2.25 Мбит/с (APB1)
UART4 RX: PC11 / TX: PC10 до 2.25 Мбит/с (APB1)
UART5 RX: PD2 / TX: PC12 до 2.25 Мбит/с (APB1)

У платы HY-MINI доступными через свободные пины являются канал USART2 (кроме линии CK: пин PA4 используется в качестве линии TP_CS для выбора сенсорной панели) и канал USART3 (полностью). Канал USART1 естественным образом разведен – именно по нему происходит коммуникация с компьютером (PA9->USART1_TX; PA10->USART1_RX; PA11->USB_DM; PA12->USB_DP).

Возможность воспользоваться каналами UART4/5 невелика, так как “их” пины заняты для коммуникации с SD-карточкой, а именно UART4: PC10 используется в качестве SDIO_D2, а PC11 – как SDIO_D3.

UART5: PC12 используется в качестве SDIO_CK, а PD2 – как SDIO_CMD.

Конечно, остается возможность ремаппинга каналов, однако она доступна только для каналов USART1…3, а стало быть, имеет смысл только для USART1.

Инициализация USART1 выглядит следующим образом:

void Usart1Init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef  USART_ClockInitStructure; #ifdef BUFFERED //конфигурируем NVIC NVIC_InitTypeDef NVIC_InitStructure; //создаем буферы для приема и передачи символов BufferInit(&U1Rx); BufferInit(&U1Tx); #endif //разрешаем тактирование шины

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

// настройка пинов, используемых USART-каналом

//настраиваем пин PA09 (USART1->Tx) на выход (AF push-pull) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //настраиваем пин PA10 (USART1->Rx) на вход (input floating) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_ClockStructInit(&USART_ClockInitStructure);

USART_ClockInit(USART1, &USART_ClockInitStructure);

// теперь очередь настраивать USART-канал

USART_InitStructure.USART_BaudRate = 9600; // USART_InitStructure.USART_BaudRate = 2400; // USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Write USART1 parameters USART_Init(USART1, &USART_InitStructure); //Enable USART1 USART_Cmd(USART1, ENABLE); #ifdef BUFFERED //select NVIC channel to configure NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //set priority to lowest NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; //set subpriority to lowest NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; //enable IRQ channel NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //update NVIC registers NVIC_Init(&NVIC_InitStructure); //disable Transmit Data Register empty interrupt USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //enable Receive Data register not empty interrupt USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); #endif

}

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

Источник: http://mcu8.ru/wp-gull/mylinks/2012/08/27/stm32f103vct6-programmirovanie-usart/

STM32 программирование USART

В микроконтроллерах STM32 имеется не менее одного USART порта.  Главное отличие их в том, что только USART1 подключен к высокоскоростной шине APB2. Все остальные USART подключены к APB1. Для использования USART в STM32 необходимо прежде всего

  • Включить тактиованте шины для USART1
  • Настроить выводы RX / TX для USART1
  • Установите скорость передачи данных для USART1
  • Включить USART1 и его RX-и TX-компонент

Для отправки и приема данных используется регистр DR (Data Register) соответствующего порта USART . При его чтении получаем последний полученный байт. Для передачи байта мы его записываем в этот регистр . Возникает проблема  –  из-за того, что новые данные могут быть записаны в регистр до того как будут прочитаны принятые данные. Одно из решений (неэффективных) проблемы – использовать задержку после записи в регистр байта для передачи перед тем как послать следующий байт или принять ответный байт. Более рациональное решение – использование SR (Status Register) регистра состояния соответствующего USART. Регистр состояния имеет бит, устанавливаемый , если данные передаются, а также бит, устанавливаемый при получены новых данных. При чтении регистра DR, флаг (бит) получения новых данных автоматически сбрасывается. Это решение, которое мы будем использовать в дальнейшем. Кроме этого можно использовать USART1- прерывание для полученных данных. При этом обработчик прерывания вызывается каждый раз были получены новые данные.

Подключаем к проекту файл с именами системных регистров для STM32F1xx это

#include “stm32f10x.

h

void UART_init(void)
{
// USART3 init
        RCC->APB1ENR |= RCC_APB1ENR_USART3EN; // такты на USART3

        GPIOB->CRH &= (~(GPIO_CRH_CNF10_0)); //Настройка порта передатчика
        GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_CNF10_1); // AF Push-Pull out (TX)

//      GPIOB->CRH &= (~(GPIO_CRH_CNF11)); // Настройка порта приемника
//      GPIOB->CRH &= (~(GPIO_CRH_MODE11));
//      GPIOB->CRH |= (GPIO_CRH_CNF11_1); 
//      GPIOB->BSRR |= GPIO_ODR_ODR11;  // Input Pull-up  (RX)
        
        USART3->CR1 |= USART_CR1_UE; // Разрешить USART3
        USART3->BRR = 0x0271; // 57600 baud
        USART3->CR1 |= USART_CR1_TE; //Разрешить передатчик

}

Передача байта:

        while ((USART3->SR & USART_SR_TXE) != USART_SR_TXE);

        USART3->DR = 'D';

Перед началом работы с USART нужно включить ножки GPIO на вход и на выход:

USART1: PA9/TxD + PA10/RxD
USART2: PA2/TxD + PA3/RxD

USART3: PB10/TxD + PB11/RxD

В случае, если все стандартные контакты USART уже заняты, можно перенаправить их на другие — это называется ремаппинг.

USART1 в таком случае переходит на PB6/TxD + PB7/RxD, а USART3 — на PC10/TxD + PC11/RxD. USART2 нельзя ремапнуть на другие пины.

Код изменяется совсем немного: всё, что нужно сделать — это добавить строку AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; и конечно переписать код включения портов ввода-вывода на новые пины:

RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
AFIO->MAPR  |= AFIO_MAPR_USART1_REMAP;
GPIOB->CRL  |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6_0 | GPIO_CRL_CNF7_0;

int main(void)
{
  // Настраиваем ножку PC8 в режим выхода на светодиод на плате
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  // Включаем модули USART1 и GPIOA, а также включаем альтернативные функции выходов
  RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
  // Контакт PA9 будет выходом с альтернативной функцией, а контакт PA10 – входом
  GPIOA->CRH &= !GPIO_CRH_CNF9;
  GPIOA->CRH  |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0 | GPIO_CRH_CNF10_0;
  // Настраиваем регистр тактирования, скорость составит 9600 бод (при тактовой частоте 24 МГц)
  USART1->BRR = 0x9C4;
  // Выключаем TxD и RxD USART
  USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
  // Запускаем модуль USART
  USART1->CR1 |= USART_CR1_UE;
  // Разрешаем прерывание по приёму информации с RxD
  USART1->CR1 |= USART_CR1_RXNEIE;
  // Назначаем обработчик для всех прерываний от USART1
  NVIC_EnableIRQ(USART1_IRQn);
  USART1_Send_String(“Start
“);
  // Бесконечный цикл
  while(1);
}

void USART1_Send(char chr) {
  while(!(USART1->SR & USART_SR_TC));
  USART1->DR = chr;
}

void USART1_Send_String(char* str) {
  int i=0;
  while(str[i])
    USART1_Send(str[i++]);
}

// Обработчик всех прерываний от USART1
void USART1_IRQHandler(void) {
  // Выясняем, какое именно событие вызвало прерывание. Если это приём байта в RxD – обрабатываем.
  if (USART1->SR & USART_SR_RXNE) {
    // Сбрасываем флаг прерывания
    USART1->SR&=~USART_SR_RXNE; 

    // Получаем принятый байт
    if(USART1->DR=='1') {
      GPIO_SetBits(GPIOC, GPIO_Pin_9);
      // Отправляем обратно строку “On” с переводом строки
      USART1_Send_String(“On
“);      
    }
    if(USART1->DR=='2') {
      GPIO_ResetBits(GPIOC, GPIO_Pin_9);
      USART1_Send_String(“Off
“);
    }
  }
}

#include “stm32f10x.h”
#include “stm32f10x_gpio.h”
#include “stm32f10x_rcc.h”
#include “stm32f10x_usart.h”
//Макрос для проверки состояние определенного светодиода.

#define   get_led_state(pin) ((GPIOB->ODR & pin) != 0)

//Функция отправляет байт в UART
void send_to_uart(uint8_t data)  {
 while(!(USART1->SR & USART_SR_TC));
 USART1->DR=data;
}

//Функция отправляет строку в UART
void send_str(char * string) {
 uint8_t i=0;
 while(string[i]) {
  send_to_uart(string[i]);
  i++;
 }
 send_to_uart('
');
 send_to_uart('
');
}

int main(void)
{
 uint8_t uart_data;
 uint16_t led;
 //Включаем порты и UART1
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB  , ENABLE);
 //Выключаем JTAG (он занимает ноги нужные нам)
 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

 //Настраиваем первые 10 ног порта B на выход
 GPIO_InitTypeDef gpio_port;
 gpio_port.GPIO_Pin = 0x3FF;
 gpio_port.GPIO_Mode = GPIO_Mode_Out_PP;
 gpio_port.GPIO_Speed = GPIO_Speed_2MHz;
 GPIO_Init(GPIOB, &gpio_port);
 GPIOB->ODR=0x00;

    // Настраиваем ногу PA10 как вход UARTа (RxD)
 gpio_port.GPIO_Pin   = GPIO_Pin_10;
 gpio_port.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &gpio_port);

    // Настраиваем ногу PA9 как выход UARTа (TxD)
    // Причем не просто выход, а выход с альтернативной функцией

    gpio_port.GPIO_Pin   = GPIO_Pin_9;
    gpio_port.GPIO_Speed = GPIO_Speed_50MHz;
    gpio_port.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &gpio_port);

    //Заполняем структуру настройками UARTa
    USART_InitTypeDef uart_struct;
    uart_struct.USART_BaudRate            = 9600;
    uart_struct.USART_WordLength          = USART_WordLength_8b;
    uart_struct.USART_StopBits            = USART_StopBits_1;
    uart_struct.USART_Parity              = USART_Parity_No ;
    uart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    uart_struct.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
    //Инициализируем UART
    USART_Init(USART1, &uart_struct);
    //Включаем UART
    USART_Cmd(USART1, ENABLE);

    while(1) //Бесконечный цикл в нем мы проверяем …
    {
     if (USART1->SR & USART_SR_RXNE) { // … не пришло ли что-то в UART ?
      uart_data=USART1->DR; //Считываем то что пришло в переменную…
      switch(uart_data)  { //И выполняем определённое действие…
      case '0':
       GPIOB->ODR^=GPIO_Pin_0;  //Инвертируем состояние ноги №0
       break;
      case '1':
       GPIOB->ODR^=GPIO_Pin_1;
       break;
      case '2':
       GPIOB->ODR^=GPIO_Pin_2;
       break;
      case '3':
       GPIOB->ODR^=GPIO_Pin_3;
       break;
      case '4':
       GPIOB->ODR^=GPIO_Pin_4;
       break;
      case '5':
       GPIOB->ODR^=GPIO_Pin_5;
       break;
      case '6':
       GPIOB->ODR^=GPIO_Pin_6;
       break;
      case '7':
       GPIOB->ODR^=GPIO_Pin_7;
       break;
      case '8':
       GPIOB->ODR^=GPIO_Pin_8;
       break;
      case '9':
       GPIOB->ODR^=GPIO_Pin_9;
       break;
      case '?': //Печатаем состояние каждого светодиода
       send_str(“===LEDs state:===”);
       for (led=1;led

Источник: https://arm-stm.blogspot.com/2013/11/stm32-usart.html

Примеры использования StdPeriph — USART

В данной серии статей будут приведены примеры работы с периферией STM32L с помощью библиотеки, предоставляемой ST — StdPeriph. Перед использованием примеров не забывайте включать, соответствующие файлы библиотеки в проект.

GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //вкл тактирования USARTx RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //вкл тактирования портов ножек USARTx GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //(указать ножки USART)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //(AF – альтернативная функция ножек)
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; //(max частота тактирования ножек)
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //(_PP – push/pull output, _OD – open drain output)
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); USART_InitStruct.USART_BaudRate = 9600; USART_InitStruct.USART_WordLength = USART_WordLength_8b; //(_9b)
USART_InitStruct.USART_StopBits = USART_StopBits_1; //(_0_5, _2, _1_5)
USART_InitStruct.USART_Parity = USART_Parity_No; //(_Even, _Odd)
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //(_RTS, _CTS, _RTS_CTS)
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE); while(!USART_GetFlagStatus(USART3, USART_FLAG_RXNE)); // прием
x = USART_ReceiveData(USART3); USART_SendData(USART3, x); // передача
while(!USART_GetFlagStatus(USART3, USART_FLAG_TC)); // передача последовательных данных
float Temp; unsigned char* ptr;// 8 бит, для передачи (адрес) ptr = (unsigned char *) &Temp; // float более 8 бит поэтому приводим к 8 битам и поэтапно передаем data_usart = *ptr; USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)); data_usart = *(ptr+1);
USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)); data_usart = *(ptr+2);
USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)); data_usart = *(ptr+3);
USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));

прерывание USART

// настройка прерывания по usart
void USART_1_nvic(void)
{ NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); /* Enable the USART2 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // включение прерывания по приему и по передачи USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //USART_ITConfig(USART1, USART_IT_TXE, ENABLE); при передаче разрешить
} void USART1_IRQHandler(void)
{ /* Прерывание по приему байта по USART */ if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { USART_ClearFlag(USART1, USART_IT_RXNE); // func(); – функция обработчик } if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) { USART_ClearFlag(USART1, USART_IT_TXE); // func(); – функция обработчик }
}

Прерывания от TXE — буфер передачи USART пуст, происходит сразу после разрешения данного прерывания, конечно, если вы ничего не передаете в данный момент. Поэтому, для того что-бы передать данные вы создаете буфер с данными, которые надо передать. Разрешаете прерывание USART_IT_TXE:

USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

В функции обработчика прерывания на передачу, передаете данные из буфера на USART:

USART_SendData(USART1, send_buf[i]);

После того как вы передали все необходимые данные, не забудьте отключить прерывания. Иначе, поскольку буфер передачи USART будет пуст, прерывания будут происходить постоянно.

USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

Прием прост — при приеме данных по USART происходит прерывание и в его обработчике вы складываете данные в приемный буфер:

rec_buf[i] = USART_ReceiveData(USART1);

Note: небольшая заметка об USART:

Запись 8-N-1, значит 8 бит данных, нет проверки четности и 1 стоп бит.

Стоп битов может быть 1, 1.5, 2. Кроме того, если стоит проверка четности/нечетности, то перед стоп битом вставляется этот бит проверки. Информационных бит тоже может быть меньше 8.

Нет сообщения — высокий уровень.
Сообщение появляется — передатчик опускает линию (1 бит всегда старт бит) — старт бит.

В стандарте RS232 логическая единица передается напряжением -12В.

STM32Записки эмбеддераПамятка

Источник: http://badembed.ru/primery-ispolzovaniya-stdperiph-usart/