STM32

STM32是STMicroelectronics(意法半导体)推出的一系列基于ARM Cortex-M内核的32位微控制器(MCU)产品。这些微控制器提供了广泛的产品系列,覆盖了多种不同的性能和功能需求,适用于各种应用领域,包括工业控制、汽车电子、消费类电子、医疗设备等。

STM32系列微控制器以其高性能、低功耗、丰富的外设接口和灵活的开发工具而闻名。它们通常具有丰富的存储器、多种通信接口(如UART、SPI、I2C、CAN等)、模拟数字转换器(ADC)、定时器、PWM输出等功能,以满足不同应用场景下的需求。

STM32微控制器通常使用标准的ARM Cortex-M内核,包括Cortex-M0、M0+、M3、M4和M7等,这些内核具有不同的性能和功耗特性,可根据具体应用的需求进行选择。此外,STM32系列还提供了多种封装和引脚配置,以满足不同尺寸和集成度的要求。

STMicroelectronics为STM32系列提供了丰富的开发工具和支持资源,包括基于ARM开发环境的集成开发环境(IDE)、调试器、评估板和参考设计等。这些工具和资源有助于开发人员快速开发和部署他们的应用,并提供了全面的技术支持和文档资料,帮助用户充分发挥STM32微控制器的性能和功能优势。

1、序言

很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不用管内容是什么!

2、硬件实现原理

“STM32之红外遥控信号自学习实现"

由上述原理图可知,当IE为高电平时发送红外光,为低电平时不发送红外光。

在NEC协议中,信息传输是基于38K载波,也就是说红外线是以载波的方式传递。

发送波形如下图所示:

“STM32之红外遥控信号自学习实现"

NEC协议规定:

发送协议数据“0” = 发送载波560us + 不发送载波560us

发送协议数据“1” = 发送载波560us+ 不发送载波1680us

发送引导码 = 发送载波9000us + 不发送载波4500us

在红外接收端,如果接收到红外38K载波,则IR输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在IR端接收的信号如下所示:

“STM32之红外遥控信号自学习实现"

“STM32之红外遥控信号自学习实现"

3、软件实现自学习

设计原理:

“STM32之红外遥控信号自学习实现"

1、 根据接收波形记录电平和电平持续时间,以便于发送。

2、电平记录采用定时器捕获功能,从下降沿接收引导信号开始,每触发一次改变触发方式,从而使每个电平变化都能捕获到。

源码实现如下:

定时器捕获初始化设置(CubeMax软件自动配置生成):

void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};


htim4.Instance = TIM4;
htim4.Init.Prescaler = 71;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 10000;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}


}

定时器捕获中断回调处理:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
    {
if(TIM4->CCER & (TIM_CCER_CC4P))   //下降沿触发
        {
            TIM4->CCER &= ~(TIM_CCER_CC4P); //切换
            gu8BitVal = 1;
        }
else                               //上升沿触发
        {
            TIM4->CCER |= TIM_CCER_CC4P;    //切换
            gu8BitVal = 0;
        }




if(gsInfrared.State == NONE_STATE)
        {
            gsInfrared.State = RECV_STATE;
        }
else if(gsInfrared.State == RECV_STATE)
        {
            NowTimCnt = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
            gsInfrared.KeepTime[gsInfrared.SampleCount] = Round(NowTimCnt);
            gsInfrared.BitValue[gsInfrared.SampleCount ++] = gu8BitVal;
        }


        TIM4->CNT = 0;
    }
}

3、设置的定时器溢出时间为10ms,如果10毫秒内不再接收电平变化则默认接收结束,设置结束标志。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim4)
    {
if(gsInfrared.State == RECV_STATE)
        {
            gsInfrared.State = END_STATE;
        }
    }
}

至此,实现了红外遥控的学习功能,获得的记录数据为记录长度和电平信号数组与电平信号维持的时间数组。

“”

“”

4、发送实现

设置定时器输出38KPWM信号,在记录电平为0是输出记录时间的38K载波信号,如果为1则不输出载波,实现如下:

PWM生成设置(CubeMax自动配置生成):

void MX_TIM5_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};


  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 0;
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 1896;
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim5);


}

发送实现,注意点就是记录为0时发载波,记录为1时不发载波:

void InfraredSend(void)
{
uint16_t Count = 0;

while(Count < gsInfrared.SampleCount &&  gsInfrared.State == END_STATE)
    {
if(gsInfrared.BitValue[Count] == 0)
        {
            TIM5->CCR2 = 948;
            delay_us(gsInfrared.KeepTime[Count]);
            TIM5->CCR2 = 0;
        }
else
        {
            TIM5->CCR2 = 0;
            delay_us(gsInfrared.KeepTime[Count]);
            TIM5->CCR2 = 0;
        }


        Count ++;
    }


    delay_us(20000);
}

往PWM比较寄存器设置948即为设置38KPWM波,也可在初始化时固定948,在此函数内启停定时器即可;

至此,自学习功能的全部思路已实现,通过对各个不同类型的红外遥控进行功能测试,均成功。

PS:查看很多资料发现很多红外解码未判断低电平时间,个人感觉不是很好,应该是不仅高电平时间得符合,低电平时间也应该符合。

自己写了一个小函数验证了一下,这个函数只是验证,未经仔细推敲,还可优化,仅供参考这一思想。

误差设计:±200us(拍脑袋值)

void InFraredDataDeal(void)
{
uint32_t DataBuff = 0;
uint16_t Count = 0;


if(gsInfrared.State == END_STATE)
    {
        gsInfraredData.State = 0;


do
        {
switch(gsInfraredData.State)
            {
case 0:   //引导码识别
            {


if(gsInfrared.KeepTime[0] >= 8800 && gsInfrared.KeepTime[0] <= 9200 && gsInfrared.BitValue[0] == 0)
                {
if(gsInfrared.KeepTime[1] >= 4300 && gsInfrared.KeepTime[1] <= 4700 && gsInfrared.BitValue[1] == 1)
                    {
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
                        {
                            Count = 3;
                            gsInfraredData.State = 1;
                        }
                    }
else if(gsInfrared.KeepTime[1] >= 2300 && gsInfrared.KeepTime[1] <= 2700 && gsInfrared.BitValue[1] == 1)
                    {
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
                        {
                            gsInfraredData.ReDataCount ++;
                            gsInfraredData.State = 3;
                        }
                    }
else
                    {
                        gsInfraredData.State = 3;
                    }


                }
else
                {
                    gsInfraredData.State = 3;
                }




            }
break;




case 1:   //数据解析
            {


if(gsInfrared.KeepTime[Count + 1] >= 360 && gsInfrared.KeepTime[Count + 1] <= 760 && gsInfrared.BitValue[Count + 1] == 0)
                {


if(gsInfrared.BitValue[Count] == 1)
                    {
if(gsInfrared.KeepTime[Count] >= 1480 && gsInfrared.KeepTime[Count] <= 1880)
                        {
                            DataBuff <<= 1;
                            DataBuff |= 1;
                        }
else if(gsInfrared.KeepTime[Count] >= 360 && gsInfrared.KeepTime[Count] <= 760 && gsInfrared.BitValue[Count] == 1)
                        {
                            DataBuff <<= 1;
                            DataBuff |= 0;
                        }
else
                        {
                            gsInfraredData.State = 3;
                        }
                    }
                }


if(Count < gsInfrared.SampleCount)
                {
                    Count += 2;
                }
else
                {
                    gsInfraredData.State = 2;
                }


            }
break;


case 2:   //成功解析
            {
                gsInfraredData.Data = DataBuff;
                gsInfraredData.State = 3;


            }
break;


default:
            {
                gsInfraredData.State = 3;   //解析结束


            }
break;
            }


        }
while(gsInfraredData.State != 3);


        gsInfrared.State = NONE_STATE;
        gsInfrared.SampleCount = 0;
    }


}

解析的话一般高位在前,所以左移,经测试帧格式为:引导码+用户码+用户码反码+命令码+命令码反码,能成功解析数据!解析的话根据具体协议,具体分析。

来源:博客园(博主:树荫下的阳光)
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 340

可能很多人都不习惯使用Keil、IAR自带的编辑器,可能代码补全、错误提示、高亮等编辑功能相对来说支持的不是很好。

虽然Keil MDK 从 V5.25版本开始对编辑功能改善了很多,但是很多人还是青睐于第三方的编辑器。

使用第三方的编辑器,如果需要编译和下载,就需要借助通过额外的方式实现,比如本文即将描述的通过命令行编译和下载的方式,可以让我们在使用第三方编辑器编辑的时候,进行代码编译和下载。

下面我们来描述以下内容:

  • 常用代码编辑器

  • Keil 命令行编译下载

  • IAR 命令行编译下载

  • 编译下载使用方法

1、常用的代码编辑器

下面介绍几款常用的代码编辑器:

1.VS Code

VS Code 是绝大部分软件工程师都在使用的一款软件编辑器工具,VS Code 全称 Visual Studio Code,是微软开发的一套免费、轻量级、功能强大的源代码编辑器工具。

网址:
https://code.visualstudio.com

“STM32通过命令行编译和下载

2.Source Insight

Source Insight是一款功能强大的代码编辑器、浏览器和分析器,可在你代码编辑时快速理解代码。同时,Source Insight具有针对C/C++、 C#、 Java、Objective-C等语言的动态分析功能。

网址:

https://www.sourceinsight.com

“STM32通过命令行编译和下载

3.Vim

Vim是从 vi 发展出来的一个文本编辑器,它是一个高度可配置的文本编辑器工具,旨在使创建和更改任何类型的代码(和文本)非常高效。在大多数UNIX、Linux系统和Apple OS X中,都集成了Vi。

网址:

http://www.vim.org

“STM32通过命令行编译和下载

4.Sublime Text

Sublime Text 也是一款优秀的、轻量级的跨平台的编辑器。它是一个跨平台的编辑器,支持windows、linux和Mac操作系统。

网址:

https://www.sublimetext.com

“STM32通过命令行编译和下载

2、Keil 命令行编译下载

编译:

UV4 〚command〛 〚projectfile〛 〚options〛
UV4.exe -r Blinky.uvproj -o Build_Output.txt

UV4.exe : 前面需要补全路径
-r Blinky.uvproj :Keil 工程名
-o Build_Output.txt:输出文档

下载:

UV4.exe -f Programming.UVPROJ -o Prg_Output.txt\

参考资料:
http://www.keil.com/support/man/docs/uv4/uv4_commandline.htm

3、IAR 命令行编译下载

编译:

IarBuild.exe test.ewp -build Debug -log all

IarBuild.exe :前面需要补全路径
test.ewp :工程名,注意是.ewp结尾的。
-build Debug :表示build
-log all :打印所有,可以设置 -log info

下载:

在Setting 文件夹下面有一个.cspy的bat文件,在后面加上参数 "--download_only",前提是在IAR下面都配置好了,并且成功下载过一次的工程。

--download_only

4、使用方法

我们可以在工程所在的路径下面编写bat文件,通过直接运行bat就可以编译和下载了,第三方编辑器通常都可以配置编译选项和调试选项,也可以配置在Tool里面进行编译下载,我比较喜欢使用powershell进行编译和下载。

可能每个人习惯不同,对工具的使用也不同,这种方法,如果感兴趣你可以试试。

参考来源:
https://www.cnblogs.com/memorypro/p/9562919.html

编排 | strongerHuang
微信公众号 | 嵌入式专栏
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 698

本应用笔记中包含的一些指南用于检验下表列出的所选STM32微控制器(MCU)中嵌入的RNG外设生成的数字的随机性。

详阅请点击下载《使用NIST统计测试集验证STM32微控制器随机数生成》

来源:ST
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 20

开发低功耗产品,我们会比较关注整个系统的功耗问题。那么,LPTIM低功耗定时器你有关注吗?

1、写在前面

在早些年,可能较少听见LPTIM这个名词。随着低功耗产品需求越来越严格,MCU厂商就推出了针对低功耗应用的LPTIM定时器。

定时器是我们常见的一种外设,之所以这么常见,原因在于定时器的用途非常广泛。

在STM32所有MCU中都配有定时器,那么你有关注、对比过各系列,各型号MCU中定时器的差异吗?

2、哪些STM32配有LPTIM定时器

在STM32中,相对较新的MCU部分型号配有LPTIM定时器。

比如:STM32F7、H7高性能MCU,STM32L0、 L4低功耗MCU,以及新推出的G0、G4系列中都配有这种LPTIM定时器。

具体哪些MCU配有LPTIM,大家可以下载对应的数据手册查看。

本文围绕STM32G0讲述其中的LPTIM定时器。

3、LPTIM功能

LPTIM:Low-power timer,即低功耗定时器。

LPTIM 是一个 16 位定时器,得益于其定时器的低功耗。

由于 LPTIM 的时钟源具有多样性,因此 LPTIM 能够在所有电源模式(待机模式除外)下保持运行状态。

即使没有内部时钟源, LPTIM 也能运行,鉴于这一点,可将其用作“脉冲计数器”,这种脉冲计数器在某些应用中十分有用。

此外, LPTIM 还能将系统从低功耗模式唤醒,因此非常适合实现“超时功能”,而且功耗极低。

LPTIM 引入了一个灵活的时钟方案,该方案能够提供所需的功能和性能,同时还能最大程度地降低功耗。

我仔细对比了一下STM32各系列的LPTIM低功耗定时器,发现很多功能基本一样。

1)框图

STM32G0低功耗定时器框图:

“STM32低功耗定时器(LPTIM)有哪些独特功能?"

STM32L0低功耗定时器框图:

“STM32低功耗定时器(LPTIM)有哪些独特功能?"

对比框图,可以发现这个LPTIM片上外设有相似之处。

当然,有些细节是不一样的,像在STM32H7中有多个LPTIM,这几个LPTIM之间是有一定差异的。

2)LPTIM 主要特性

  • 16 位递增计数器

  • 3 位预分频器,可采用 8 种分频系数(1、 2、 4、 8、 16、 32、 64 和 128)

  • 可选时钟

– 内部时钟源:LSE、 LSI、 HSI 或 APB 时钟

– LPTIM 输入的外部时钟源(在没有 LP 振荡器运行的情况下工作,可在使用脉冲计数器应用场景中使用)

  • 16 位 ARR 自动重载寄存器

  • 16 位比较寄存器

  • 连续/单触发模式

  • 可选软件/硬件输入触发

  • 可编程数字防抖动干扰滤波器

  • 可配置输出:脉冲和 PWM

  • 可配置 I/O 极性

  • 编码器模式

拿这些特性和其它基本定时器相对较,你会发现,这些特性中很多都是LPTIM独有的。

3)LPTIM RCC

LPTIM的RCC和其他定时器相比较,其RCC功能更加丰富。

通过上面框图可以发现,LPTIM 可通过多个时钟源提供时钟。

它可以由内部时钟信号提供时钟,内部时钟信号可通过复位和时钟控制器 (RCC) 在 APB、 LSI、 LSE 或 HSI 时钟源中进行选择。

4)干扰滤波器

这个功能也是LPTIM所特有的一个功能。

LPTIM 输入由数字滤波器保护,避免任何毛刺和噪声干扰在 LPTIM 内部传播,从而防止产生意外计数或触发。

滤波示意图:

“STM32低功耗定时器(LPTIM)有哪些独特功能?"

这个原理比较简单,如果不能理解请查看参考手册详解。

LPTIM定时器的功能比较多,可能初学者一看到那么多内容就吓到了。其实,把内容拆开来看并不难。

本文旨在让更多朋友知道这些功能,想要深入掌握其中知识,需结合手册和实践编程。

来源:strongerHuang
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 717
  • 扩展后的STM32Cube 生态系统可支持 STM32WB 无线 MCU
  • 新的 STM32CubeWB 固件,升级的编程器和射频测试工具
  • 改进的无线功耗估算器准确计算电池续航时间

服务多重电子应用领域的全球半导体领导者意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM) 发布了新的STM32WB无线微控制器(MCU)开发工具和软件,为智能建筑、智能工业和智能基础设施的开发者降低设计经济、节能的无线设备的难度。

“意法半导体市场领先的

意法半导体的高集成度 STM32WB 单片集成一个 2.4GHz射频收发器和Arm® Cortex®-M4 和Cortex-M0+ 双核微控制器,从而消除了诸多射频电路设计挑战,因为射频电路设计会增加项目的开发时间,而且会给项目开发带来很多不确定性。而用STM32WB开发硬件设计只需要少量的外部组件,例如,选择天线。STM32WB MCU 配备许多外设,包括 12 位模数转换器 (ADC)、数字接口和无晶振 USB 2.0 全速接口,具体根据所选型号而定。芯片支持的协议包括 Bluetooth® LE 5.2、Zigbee®、OpenThread 和专有协议,包括这些协议组合的并发模式。

STM32家族是市场领先的Arm Cortex-M微控制器,作为该产品家族的成员,STM32WB 基于经过市场检验的、受到广泛支持的开发工具和软件资源丰富的STM32Cube 生态系统。

意法半导体 STM32 无线市场总监 Hakim Jaafar 表示:“STM32Cube 生态系统已经被广泛使用,并得到第三方开发者资源的广泛支持,这有助于加快项目开发。我们新推出的经过强化的无线产品扩展了 STM32 系列处理新需求和用例的能力,进一步增强了稳健的STM32 解决方案的市场领先地位。”

技术详情:生态系统新特性助力无线设计

STM32WB 生态系统加强了对无线设计的支持力度,提供了所有必要的嵌入式软件模块和工具,让用户可以轻松地开发应用。在STM32CubeWB MCU软件包里面有很多代码示例,并提供一整套外设驱动程序(HAL 和 LL)和所有的必要的射频协议栈,包括用于蓝牙 5.2、Zigbee 3.0、OpenThread v1.1 和专有协议的 802.15.4 MAC,以及多个实现这些协议栈并发模式(静态和/或动态)的例程。STM32CubeMX and STM32CubeIDE等软件工具的GUI界面直接支持射频协议栈,方便访问和配置这些协议栈。用户可以轻松地选择和配置Profiles和Clusters,以支持主流的标准,并受益于现成的代码示例。

STM32CubeMX 配置器为功耗估算工具增加了额外的控制功能,有助于计算射频子系统对整体功耗预算的影响。用户可以设置各种场景来准确评估电池续航时间。

此外还有更多新功能,例如,STM32Cube 编程器的强化功能可以优化对STM32WB 双核架构的编程功能,利用Cortex-M0+ 处理器与Cortex-M4 主内核一起控制射频子系统,确保实时应用性能。

借助 STM32CubeMonitor-RF评估工具,生态系统将开发过程拓展到在客户环境中高效安装射频并测试性能。STM32CubeMonitor-RF 支持Bluetooth® LE和通用 802.15.4 射频技术,可执行收发测试和射频性能测量,并协助编写测试脚本、测试协议和命令序列。最新版本为 802.15.4 协议引入了侦测器功能,降低网状网络产品的开发难度。

STM32CubeWB 无线生态系统中的所有工具和射频协议栈都取得了相关认证并免费提供,以及随附蓝牙 5.2 和 802.15.4 认证项目的详细说明文档,使客户能够快速且经济地获得适用的射频产品许可证书。

STM32WB 无线微控制器生态系统还包含一套 STM32WB 无线微控制器评估板,帮助用户加快无线产品的开发速度。

含有Nucleo-64开发板和USB适配器、NUCLEO-WB55RG 开发板和 NUCLEO-WB15CC Nucleo-64 开发板的P- NUCLEO-WB55开发套件,以及 STM32WB5MM-DK探索套件 ,为用户提供立即开发应用的各种功能,适合各种无线应用。

使用同一系列芯片,各种应用设计都可以共用同一个基础设计,充分利用产品开发和认证投资。

STM32WB 产品的灵活性很高,从高端到成本敏感的不同类型产品均可使用,应用前景广阔。

详情访问www.st.com/stm32wb.

关于意法半导体

意法半导体拥有46,000名半导体技术的创造者和创新者,掌握半导体供应链和先进的制造设备。作为一家独立的半导体设备制造商,意法半导体与十万余客户、数千名合作伙伴一起研发产品和解决方案,共同构建生态系统,帮助他们更好地应对各种挑战和新机遇,满足世界对可持续发展的更高需求。意法半导体的技术让人们的出行更智能,电力和能源管理更高效,物联网和5G技术应用更广泛。详情请浏览意法半导体公司网站:www.st.com

围观 20

前言

UART是重要的片上资源,主流单片机基本上都有该功能,通过UART可以扩展出很多的通信接口,如RS232、RS485、LIN,甚至WIFI、蓝牙模组等,可以说只要搞通讯就会涉及到UART。下面和大家分享STM32的UART配置。

1、UART是什么

USART全称universal synchronous asynchronous receiver transmitter通用同步异步接收发送器;速率最高可达4.5Mbits/s,波特率460800;

数据按位顺序发送的串行通信接口简称串口,USART模块是采用串行通信接口最常见的模块,为了方便,就把USART简称为串口;

USART接口通过RX,TX,GND同其他设备相连;当TX引脚被禁止时,该引脚恢复GPIO的配置;当TX引脚使能且未发送数据时,该引脚处于高电平(空闲态);

USART接口的数据字长度可编程,停止位长度可编程;可配置为DMA多缓冲通信;

2、USART的帧格式

串口数据应该遵循USART帧的格式,才能被串口识别;

首先总线需要持续至少一个空闲帧,然后连续发送数据帧,数据帧与数据帧之间有时会有断开帧,断开帧后需要接1-2bit停止位,连接下个数据帧;

断开帧只能为10bit或11bit低电平的帧(CR1_SBK[0]);然后接1或2bit的高电平作为停止位,然后接下一个数据帧;

数据帧的数据字有两种格式,(1)8 bit 数据位;(2)8bit 数据位 + 1 bit 奇偶校验位;

“STM32单片机,UART的寄存器配置以及工作原理"

3、USART的寄存器使用

每个USART都有7个自己的寄存器;用来配置该USART的所有功能;

有许多功能诸如硬件流控制,LIN模式,智能卡模式等,由于没用过或是用不上,实在晦涩难懂费时费力,故在此全部跳过;

以下给出了USART作为常用串口收发数据的工作框图,以及相关的寄存器配置;

3.1 工作框图

“STM32单片机,UART的寄存器配置以及工作原理"

“STM32单片机,UART的寄存器配置以及工作原理"

3.2 相关寄存器配置

1)首先需要配置USART的6个参数:

波特率USART_BRR,字长M,停止位STOP,校验位PCE,PS,PEIE,USART的收发模式TE和RE和硬件流控制CTSIE,CTSE,RTSE;

2)USART提供了8个中断:TXEIE, TCIE, RXNEIE, PEIE, IDLEIE, CTSIE, LBDIE, EIE;8个中断使能均可以进入USART的中断函数,根据需要配置合适的中断使能位为1;通常为RXNEIE位;

3)然后使能接收器RE和发送器TE;

4)然后使能UE中断;

“STM32单片机,UART的寄存器配置以及工作原理"

4、USART的代码示例

4.1 标准库提供的常用USART接口

标准库为所有的外设都提供了封装寄存器的API接口函数,文件名为stm32f10x_peripheral.c;

以下为usart外设的常用函数;

//串口USARTx的参数配置初始化函数;
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
//使能串口,(主要是分频器和输出的设置)
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
//使能串口中断,(就是那8个中断,均可以进入中断函数)
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
//都是处理一个字节;
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
//读取SR寄存器的状态,SR的状态都是硬件设置的;
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
//读取SR寄存器和CRx控制寄存器的状态,和上面一个功能相同的;
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

//修改SR寄存器的状态,单功能通讯用不上;
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);

4.2 USART1使用代码

#include "usartDemo.h"  
u8 USART1_RX_BUF[256];    //接收缓存
u8 USART1_RX_CNT = 0;    //接收字节计数
u8 USART1_REV_0D = 0;    //收到\r
u8 USART1_REV_0A = 0;    //收到\r和\n

//usart1初始化之后,便可以通过串口读写了;
void Usart1_Init(u32 bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置NVIC中断分组2:2位抢占优先级,2位响应优先级   0-3;

    //USART1外设中断配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;    //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;            //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);  

    //GPIO初始化 USART1_TX    PA9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //输出需要配置速率,输入不需要配置速率;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出,<中文..手册>8.1.11外设的GPIO配置
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //GPIO初始化    USART1_RX    PA10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        //浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);

   //USART1初始化
    USART_InitStructure.USART_BaudRate = bound;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   //CR1中的TE,RE  
    USART_Init(USART1, &USART_InitStructure); 

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//CR1中的RXNEIE中断
    USART_Cmd(USART1, ENABLE);                    //CR1中的UE
}

void USART1_Send_Data(u8 *buf,u16 len)
{
    u16 t;
    for(t=0;t<len;t++)        
    {
        USART_SendData(USART1,buf[t]);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 
        //发送字节完成后,TC硬件置1;
    }    //先读SR,后写DR清除TC位;
    USART1_RX_CNT = 0;
    USART1_REV_0D = 0;
    USART1_REV_0A = 0;  
}

void USART1_IRQHandler(void)                    
{
    u8 Res;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
     {
         Res =USART_ReceiveData(USART1);        //读DR,硬件清0 RXNE位;
        USART1_RX_BUF[USART1_RX_CNT]=Res;    //接收数据  
        USART1_RX_CNT++; 
        if(Res==0x0d)
            USART1_REV_0D = 1;
        if(USART1_REV_0D&&(Res==0x0a))
            USART1_REV_0A = 1;                      
     }
    //RXNE为1,读数据的同时又来了数据,那么新的数据丢失;产生溢出错误,读完数据后RXNE为0,但ORE标志还在;
    //RXNE为1,又来了数据,产生接收溢出错误,置位ORE;
    if(USART_GetFlagStatus(USART1,USART_FLAG_ORE) == SET)
    {
        USART_ReceiveData(USART1);
    //    USART_ClearFlag(USART1,USART_FLAG_ORE);//先读SR,后读DR,可以复位ORE位;应该不用软件清除了;
    }
    // USART_ClearFlag(USART1,USART_IT_RXNE); //读DR可以清除RXNE,应该不用软件清除了;
}

int main(void)
{
    Usart1_Init(460800);
    while(1)
    {
        if(USART1_REV_0A)
        {
            USART1_Send_Data(USART1_RX_BUF,USART1_RX_CNT);
        }
    }    
}

4.2.1 在前面代码的基础上不使用串口中断,直接通过SR状态位来判断数据的收发;

将上面代码的usart1初始化代码中CR1的RXNEIE配置行注释掉,然后修改main函数如下即可;

int main(void)
{
    Usart1_Init(460800); 
    while(1)
    {
        if ((USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET))
        {
            USART1_RX_BUF[USART1_RX_CNT] = USART_ReceiveData(USART1);
            if(USART1_RX_BUF[USART1_RX_CNT]==0x0a)
                USART1_REV_0A = 1;
            USART1_RX_CNT++;
        }
        if(USART1_REV_0A)
        {
            USART1_REV_0A = 0;
            for(int i=0;i<USART1_RX_CNT;i++)
            {
                USART_SendData(USART1, USART1_RX_BUF[i]);
                while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
            }
            USART1_RX_CNT=0;
        }
    }
}

5、总结

USART的功能没想到还挺多的,寄存器看起来就有些费时了,很多概念都是新的,不好理解,直接拉低了效率;于是觉得这样不行,应该用什么看什么,用到再看,学海无涯,精力有限;

另外人家费心费力写好标准库不就是为了帮开发人员省时间吗?了解一下即可,以后没必要深入;

本文代码github:https://github.com/caesura-k/stm32f1_usart

来源:玩转嵌入式
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 707

页面

订阅 RSS - STM32