CW32

例程资料链接如下(群文件也可下载):

BD网盘链接:

https://pan.baidu.com/s/1YZJtAhO3Wsjy5aBuTJ-c_Q?pwd=rm7q \

提取码:rm7q

一、实验简介

1.公交站人流检测是一项重要的城市交通管理任务,它不仅关系到公交服务的效率和质量,还与城市交通规划和公共安全紧密相关。首先,公交站人流检测可以实时反馈乘客流量情况,帮助公交公司了解各线路、各站点的客流需求。其次,公交站人流检测可以为公交公司制定和优化运营策略提供数据支持。再次,公交站人流检测可以及时发现拥挤、拥堵等情况,提醒调度中心及时采取措施,保障乘客安全。基于此背景,我们以CW32单片机为核心,采用公交站人流检测中常见的红外线检测技术,设计了一个公交站人流检测系统,该系统可以连接到网络获取当前时间,并将人流数据实时上传到OneNET云平台进行远程监控。

二、实验器材

本实验使用到了CW32-48F大学计划开发板、ESP8266WIFI模块、E18-D80NK红外光电开关及Keil5开发环境。

1.png

CW32-48F大学计划板 

2.png

ESP8266WIFI模块

3.png

E18-D80NK红外光电开关

4.png

E18-D80NK红外光电开关

5.png

实物图

开发板上预留了ESP8266WIFI模块接口,通过串口与ESP8266通信。

 6.png

【两个红外光电开关与单片机接线】:

蓝线 -- GND

棕线 -- 3.3V

黑线 -- PA0、PA4

三、核心代码

main.c:
//单片机头文件
#include "main.h"

//网络设备
#include "esp8266.h"

//网络协议层
#include "onenet.h"     //OneNET

//硬件驱动
#include "RTC.h"        //CW32RTC
#include "BTIM.h"
#include "usart.h"
#include "Buzzer.h"     //板载蜂鸣器
#include "Infrared.h"   //红外光电开关
#include "Lcd_Driver.h"
#include "LCD_calculate.h"

uint8_t send_flag=0;    //数据上云控制位
uint16_t count=0,accumulation=0;  //count--当前站内人数,accumulation--累计人数
enum State{  
    STATE_A,  
    STATE_B,  
    STATE_C,  
    STATE_D,
};         //枚举数据类型,包含四个状态

void System_Init(void)
{  
    Lcd_Init();          //LCD屏初始化  
    BTIM_Init();         //基本定时器初始化,调控数据上云频率  
    Buzzer_Init();       //蜂鸣器初始化,两个红外光电开关同时被遮挡时发出声响警告  
    Infrared_Init();     //红外光电开关初始化  
    Usart1_Init(115200); //串口1,用于串口调试助手打印调试信息  
    Usart2_Init(115200); //串口2,与ESP8266进行通信  
     
    TFT_Welcome();     //开机界面显示  
    Gui_DrawFont_GBK16(0,128,GRAY1,WHITE,"   网络连接中  ");  
    ESP8266_Init();//联网,获取当前时间,接入OneNET云平台  
    RTC_ITConfig(RTC_IT_INTERVAL,ENABLE); //开启RTC周期中断(RTC中断开启的时机要在esp8266连接到onenet平后之后)  
    Gui_DrawFont_GBK16(0,8,WHITE,BLUE," 公交站人流检测 ");  
    Gui_DrawLine(0,32,128,32,GRAY1);  
    Gui_DrawFont_GBK16(0,64,WHITE,BLUE," 站内人数:");  
    TFTShowNumber(4,12,count);  
    Gui_DrawFont_GBK16(0,96,WHITE,BLUE," 累计人数:");  
    TFTShowNumber(6,12,accumulation);  
    NVIC_EnableIRQ(BTIM1_IRQn);    //开启定时器中断,中断周期10ms
}

int main(void)
{  
    uint16_t state=0xffff;            //红外光电开关当前状态  
    enum State currentState=STATE_A;  //开机为状态A   
    System_Init();                    //系统初始化  
    while(1)  
    {        
        /*模拟乘客进站的过程:      
            1.装置安装位置:两红外光电传开关一前一后安装在站口      
            2.假设站口只允许乘客排队依次进出      
            3.乘客进站先遮挡红外光电开关1      
            4.乘客继续前进,离开红外光电开关1,遮挡红外光电开关2      
            5.站内人数+1,累计人数+1(若过程4中同时遮挡两个红外光电开关则蜂鸣器发出警报,等待工作人员解决故障,不计数)    
        */    
        /*模拟乘客出站的过程:      
            1.装置安装位置:两红外光电传开关一前一后安装在站口      
            2.假设站口只允许乘客排队依次进出      
            3.乘客出站先遮挡红外光电开关2      
            4.乘客继续前进,离开红外光电开关2,遮挡红外光电开关1      
            5.站内人数-1(若过程4中同时遮挡两个红外光电开关则蜂鸣器发出警报,等待工作人员解决故障,不计数)    
        */    
        state=CW_GPIOA->IDR & 0x0011;   //获取两个红外光电开关数据IO当前状态    
        if(state==0x0000) Buzzer_RING;  //控制蜂鸣器     
        else Buzzer_OFF;    
        switch(currentState)            //初步模仿状态机编程模式    
        {      
            case STATE_A:        
                if(state==0x0011)      currentState=STATE_B;   break;        
            case STATE_B:        
                if(state==0x0001)      currentState=STATE_C;          
                else if(state==0x0010) currentState=STATE_D;   break;      
            case STATE_C: if(state==0x0010) {count++;accumulation++;currentState=STATE_A;TFTShowNumber(4,12,count);TFTShowNumber(6,12,accumulation);}  break;      
            case STATE_D: if(state==0x0001) {if(count!=0) count--;  currentState=STATE_A;TFTShowNumber(4,12,count);}                        break;    
        }    
        if(send_flag)    
        {          
            OneNet_SendData();  //数据上传到OneNET      
            ESP8266_Clear();    //清除缓存      
            send_flag=0;      
        }  
    }
}

四、效果演示

7.png

连接网络

8.png

数据显示

来源:CW32生态社区

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

围观 37

本章介绍CW32通用异步收发器的使用。

虽然大部分时候会被简单称为“串口”,但实际上用“串口”来指代UART并不正确。串口对应并口的概念,在串口通信中,数据被以二进制形式发送,并且每次发送都只传输1比特位(当然,传输速度可能会很快),像SPI、IIC其实也属于串口。而对传输速度的描述,也就是波特率即是描述的每秒传输的比特位数量,例如波特率是9600,就代表该串口每秒可以传输9600bit的数据。与之相对应的并口,则是使用多个物理信道传输数据,一批数据会同时在多个物理信道上传输,这种并行通信会占用很多IO资源,但是传输速度也得到了显著提高。

UART作为一种异步通信方式,它不需要时钟线,在供电正常的情况下一共就只需要两根数据线,非常适合一对一的通信需求。CW32F030拥有3个UART外设,此文章介绍UART1的使用,那么按照惯例,先总览一下使用UART需要做哪些准备工作。

第一:需要将IO设置为输出,并复用为UART模式。

第二:需要使能UART这个外设,并设置通信协议的必要参数(关于UART协议本身,互联网有很多优质教程,读者可以自行搜索),完成初始化。

第三:编写发送和接收函数,调用函数实现发送和接收的功能。

第一步的进行非常简单,查询芯片《数据表》的引脚定义,发现LQFP48封装下,PA8 & PA9是UART1的发送和接收,因此只需要配置好这两个IO的功能,第一步就算是完成了。

1.png

2.png

配置代码如上图,但有读者表示自己找不到设置复用功能的函数,那我们就来看看功能复用函数的本质是什么。

3.png

这是PA9的复用函数,可以看到这是一个宏函数,其内容表明设置复用其实就是设置了对应GPIO复用寄存器的值,PA9属于A组IO的第9号口,是高位Pin口,因此要找到高位口的复用寄存器,并设置复用功能为(0010)2,也就是AF2,具体设置如下图所示。

4.png

因此配置复用的时候,如果找不到对应的复用函数,可以直接配置此寄存器来完成复用配置,但为了方便读者,配置IO复用的宏函数均位于cw32xxxxx_gpio.h这个文件中,此头文件包含了相当多的宏函数,均是常用的IO操作,如反转、置位、闪烁等,感兴趣的读者可以前往翻阅。

话题拽回到UART这边,接下来要进行的是第二步,配置UART的必要参数,这里先讲解发送功能需要进行的配置。

不论是什么单片机,想要使用任何一个片上外设,必须要使能该外设的时钟总线,直接在工程的函数列表中找到时钟配置文件下的全部函数,根据函数的名字可以快速定位使能UART1时钟的函数

我们可以看到这个函数本质上就是在操作APBEN2这个寄存器,通过查看芯片手册,我们也可以找到各个外设所属的时钟线。

5.png

6.png

随后就是UART通信参数的结构体了,结构体同样对应了寄存器,但使用结构体可以简化开发者的配置步骤,且看下图:

7.png

8.png

此结构体成员拥有相当详细的注释,这里直接按照开发者意图配置即可,我在这里配置为:波特率115200、PCLK时钟源、1个停止位、无校验位、全双工模式,配置完成后初始化结构体即可。

值得注意的是,在芯片内部并没有一个直接的波特率数值寄存器,为了保证异步通讯的可靠,波特率越精准越好,且既有的系统时钟不一定能够刚好提供波特率倍数的时基,因此实际上的波特率是一个浮点数,它拥有整数部分和小数部分的2个寄存器。具体的计算公式在芯片手册的通用异步收发器章节有写,这里只列举初始化函数中的相关操作:

9.png

由于我选择的是16倍采样,初始化函数会执行上述代码,代码的计算过程复刻了手册中的计算过程(如下图),这里是先计算时钟源在16倍采样模式下能够直接取得的波特率结果temp,temp包含了整数部分和小数部分,整数部分直接赋值即可,小数部分则是将公式变型得到的。开发者在使用时不需要手写计算BRRI和BRRF的寄存器值,初始化函数会自动完成该计算。

10.png

皆大欢喜,到目前为止已经成功完成两步了,还差最后一步就可以使用UART的发送功能了,那就是自己写一个UART1的发送函数。我手里刚好就有一个自己写的发送函数,长这个样子:

 11.png

这段简易代码会发送这个字符串作为UART1的调试参数。

12.png

这段代码的主要逻辑在芯片手册里面也有详细描述:

13.png

Tips:在编写各类通信函数这里,我建议一定要加上至少两个功能。第一个就是发送的状态,成功还是失败,这很重要,出问题之后的排查工作基本就靠这个了;第二个就是超时跳出功能,有的时候可能硬件故障或者什么别的原因导致发送一直失败,如果死等就让程序全部死掉了,超时跳出可以保证其他大部分程序的正常运行,当然使用看门狗是一种更优解。

在轮询函数中调用调试函数即可实现间隔100ms发送一次的功能,效果如下:

14.png

 15.png

从时间上来看,100ms的定时发送还是很精确的,这种方式占用CPU的时间资源实现发送,虽然传统但是有效可控。

要点总结:

1、注意区分串口和并口的概念。

2、CW32的UART虽然有2个波特率寄存器,但是并不需要开发者手算寄存器参数。

来源:CW32生态社区

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

围观 11

例程资料链接如下(群文件也可下载):

BD网盘链接:

https://pan.baidu.com/s/110FD7JQyuP-aBmEngzbsig?pwd=vi1l 

提取码:vi1l

一、实验简介

1. RC522 刷卡模块是应用于13.56MHz 非接触式通信中高集成度读写卡系列芯片中的一员,是NXP 公司针对“三表”应用推出的一款低电压、低成本、体积小的非接触式读写卡芯片。非接触式IC卡又称射频卡,由IC芯片、感应天线组成,常被用于智能仪表和便携式手持设备中,如“三表”(水表、电表、燃气表)应用。其射频卡技术,将射频识别技术和IC卡技术结合,结束了无源(卡中无电源)和免接触这一难题,为电子器件领域带来突破。卡片在一定距离范围(通常为5—10cm)靠近读写器表面,通过无线电波的传递来完成数据的读写操作。

二、实验器材

本实验使用到了CW32-48F大学计划开发板、TTS语音播报模块、RC522刷卡模块、IC钥匙扣卡及Keil5开发环境。

1.png

CW32-48F大学计划板    

2.png

TTS语音播报模块

3.png

RC522刷卡模块

4.png

IC钥匙扣卡

5.png

实物图

【RC522刷卡模块与单片机接线】:

3.3V -- 3.3V

RST -- PB15

GND -- GND

IRQ 悬空

MISO -- PB14

MOSI -- PB13

SCK -- PB12

SDA -- PA6

(注:采用SPI通信方式)

【TTS语音播报模块与单片机接线】:

黑线 -- GND

红线 -- 3.3V

黄线 -- PA9

白线 -- PA10

三、原理简介

RC522模块(射频读写器)向IC卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,这样在电磁波激励下,LC谐振电路产生共振,从而使电容内有了电荷;在这个电荷的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内存储,当所积累的电荷达到2V时,此电容可作为电源为其它电路提供工作电压,将卡内数据发射出去或接受读写器的数据。
非接触性IC卡与读卡器之间通过无线电波来完成读写操作。二者之间的通讯频率为13.56MHZ。非接触性IC卡本身是无源卡,当读写器对卡进行读写操作时,读写器发出的信号由两部分叠加组成:一部分是电源信号,该信号由卡接收后,与本身的L/C产生一个瞬间能量来供给芯片工作。另一部分则是指令和数据信号,指挥芯片完成数据的读取、修改、储存等,并返回信号给读写器,完成一次读写操作。

四、核心代码

main.c:
#include "main.h"
#include "Uart.h"
#include "stdio.h"
#include "Delay.h"
#include "RC522.h"
#include "Buzzer.h"
#include "Lcd_Driver.h"
#include "LCD_calculate.h"

#define MONRY 100    //IC卡初始金额

uint8_t RecPcd[2]={0};  //存放IC卡类型
uint8_t uid[4]={0};     //存放IC唯一序列号
uint8_t read[16]={0};   //存放读出的数据
uint8_t write[16]={0};  //存放写入的数据
uint8_t DefaultKey[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//密钥(出厂默认)

void Card_Refresh(void)     //刷新卡的余额,仅在第一次使用IC卡或者IC金额刷光后使用
{  
    write[0]=MONRY;   //将初始金额存进要写入IC卡的数组中  
    RC522_PcdWrite(0x01,write);//将数据写入块1
}

int main()
{  
    char str[16]="";   //存放显示在屏幕上的字符串  
    Lcd_Init();        //TFT屏幕初始化  
    UART3_Init();      //串口3初始化,通过串口进行语音播报  
    Buzzer_Init();     //初始化板载蜂鸣器  
    RC522_Init();       //初始化RC522刷卡模块  
    Gui_DrawFont_GBK16(0,0,BLUE,WHITE,"      BUS       ");  //显示界面  
    TFTShowString(2,0,"price: 1 RMB  ");  //单次刷卡金额  
    while(1)  
    {      
        TFTShowString(4,0,"Waiting card...");    
        if(RC522_PcdRequest(PICC_REQALL,RecPcd)==MI_OK) //寻卡,有卡就认    
        {        
            GPIO_WritePin(CW_GPIOB,GPIO_PIN_3,GPIO_Pin_SET);  //寻卡成功则蜂鸣器发出“滴”的一声      
            Delay_ms(100);      
            GPIO_WritePin(CW_GPIOB,GPIO_PIN_3,GPIO_Pin_RESET);      
            if(RC522_PcdAnticoll(uid)==MI_OK)//防冲突,应对同时有多张卡的情况,将被选中卡片的序列号保存到uid中      
            {          
                if(RC522_PcdSelect(uid)==MI_OK) //选定序列号为uid的卡片        
                {          
                    if(RC522_PcdAuthState(PICC_AUTHENT1A,0x01,DefaultKey,uid)==MI_OK)//验证该卡片第一扇区A密钥          
                    {      
                        //            Card_Refresh();  //刷新卡的余额                    
                        if(RC522_PcdRead(0x01,read)==MI_OK)     //1.读取块1(16字节)数据            
                        {              
                            write[0]=read[0]-1;                   //2.读出数据的第一字节减去(车)票价,存到写入数据的第一字节中              
                            if(RC522_PcdWrite(0x01,write)==MI_OK) //3.写入数据到块1              
                            {                
                                if(RC522_PcdRead(0x01,read)==MI_OK) //4.读出刷卡后块1的数据,进行播报和显示                
                                {                    
                                    printf("刷卡成功");//语音播报刷卡成功                  
                                    TFTShowString(4,0,"Brushing card...");                  
                                    sprintf(str,"  balance:%d",read[0]);                  
                                    TFTShowString(6,0,str);//显示卡中余额                  
                                }              
                            }            
                        }          
                    }        
                }      
            }    
        }    
        Delay_s(1); //刷卡间隔    
        TFTShowString(6,0,"                "); //覆盖余额显示  
    }
}

五、效果演示

6.png

等待刷卡

7.png

正在刷卡   

来源:CW32生态社区

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

围观 18

2023慕尼黑华南电子展(electronica South China)于10月30-11月1日在深圳国际会展中心(宝安新馆)圆满举办。

1698906095426228.jpg

CW32精彩亮相慕尼黑华南电子展

武汉芯源半导体在展位上为电子行业参观者展示了CW32众多产品应用,比如智能指纹锁、智能燃气表、LED调光板、可燃气体探测器、料位开关、温控器、无线麦克风、筋膜枪、血氧仪、以太网模块、无刷电机等多款MCU典型应用方案,吸引了众多用户驻足参观了解产品。

1698906110305925.png

1698906120359103.png

1698906131856708.png

5.png

1698906143299701.jpg

CW32荣获 最佳MCU芯片奖

2023年10月30日,由芯师爷主办、慕尼黑华南电子展协办、深圳市半导体行业协会支持的“第五届硬核芯生态大会暨2023汽车芯片技术创新与应用论坛”在深圳国际会展中心1号馆圆满落幕!

01、为客户提供负责任的产品,CW32在行动

武汉芯源半导体有限公司技术总监张亚凡在“第五届硬核芯生态大会暨2023汽车芯片技术创新与应用论坛”上发表主题演讲《为客户提供“负责任”的产品,CW32在行动》,从设计端、生产制造端和技术服务端三个环节展示了CW32系列MCU的核心优势,就CW32系列MCU的核心优势、技术性能、功能特点、产品布局等方面进行了详细讲解。

1698906169594635.jpg

02、荣获“2023年度最佳MCU芯片奖”

峰会当晚,2023年度硬核芯评选颁奖盛典隆重揭晓终极榜单。在本次评选中,武汉芯源半导体有限公司从165家企业、183款产品中脱颖而出一举斩获“2023年度最佳MCU芯片奖”。

1698906189217886.jpg

1698906197860010.jpg

03、获奖产品:通用高性能CW32F003系列

武汉芯源半导体CW32F003系列产品已全面实现 -40℃ ~105℃超宽温度范围和 1.65V~5.5V 超宽工作电压;12位高速ADC,可达到±1.0 LSB INL,11.3 ENOB(有效位数);HBM ESD 测试通过8KV,具备超强抗干扰能力,HBM ESD、MM ESD、CDM ESD、Latch up@105℃全面达到JEDEC最高等级;EFT测试通过:±4000V(Power)/±2000V(IO);具备稳定可靠的eFLASH制造,确保工业高可靠应用。

1698906207771462.png

来源:武汉芯源半导体

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

围观 10

例程资料链接如下(群文件也可下载):

BD网盘链接:

https://pan.baidu.com/s/187ePq84u2QjE1bsVPM6i3g?pwd=9jvv 

提取码:9jvv

一、实验简介

本实验是使用CW32单片机制作一个入门的遥控循迹小车。遥控采用蓝牙配合手机APP进行遥控。循迹使用一个5路的循迹模块。使用OLED模块进行显示当前小车状态。

二、实验器材

本实验使用到了CW32F030C8小蓝板、智能小车底板、电机驱动模块、OLED模块、DX-BT04-E蓝牙模块、Wch-Link下载调试器、Keil5开发环境。

1.jpg

二、接线图

【DX-BT04-E模块与单片机连线】:

GND<-->GND

5V<-->5V

TXD<-->PA3

RXD<-->PA2

2.png

【Wch-Link模块与单片机连线】:

GND<-->GND

RXD<-->PB8

TXD<-->PB9

3.png

【TB6612电机驱动模块与单片机连线】:

VM<-->VM

GND<-->GND

VCC<-->VCC

AO1<-->AO1

AO2<-->AO2

BO1<-->BO1

BO2<-->BO2

PWMA<-->PA15

AN2<-->PA11

AN1<-->PA12

STBY<-->3.3V

BN1<-->PB4

BN2<-->PB5

PWMB<-->PB3

4.png

【OLED模块与单片机连线】:

GND<-->GND

VDD<-->3.3V

SCK<-->PB6

SDA<-->PB7

5.png

【循迹模块与单片机连线】:

GND<-->GND

VDD<-->5V

S1<-->PA0

S2<-->PA1

S3<-->PA7

S4<-->PA8

S5<-->PC14

6.png

实验完整接线图:

1698804435841426.png

四、用到的外设

1.串口2:

串口2用于蓝牙模块,使手机和单片机通过蓝牙模块进行串口透传,从 而进行点对点通信。

2.高级定时器ATIM:

初始化高级定时器CH1B和CH2B进行PWM波输出,从而达到电机调速目的。

3.基本定时器BTIM1:

初始化基本定时器1,在基本定时器中断服务函数中对循迹模块进行扫描。将扫描的结果保存,以便在循迹模式中使用。

4.IIC1:

IIC1用于外挂OLED显示模块。

五、核心代码

// 基本定时器中断回调函数
// 在回调函数中对循迹模块进行扫描,将循迹模块的状态保存进sensor_data中
void BTIM1_IRQHandler(void)
{    
    if (BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV)) // 判断是否是通道1中断    
    {
        BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV); // 清除中断标志位
      
      char t = 0x00; // 设置零时变量保存灰度传感器的值
      
      // 保存灰度传感器的值        
      // 采用或运算,检测到黑线将相应的位设置为1        
      if (!GPIO_ReadPin(TRACKING_GPIOA, TRACKING_1))        
      {            
          t |= 0x08; // 00001000 左边数第一个        
      }        
      if (!GPIO_ReadPin(TRACKING_GPIOA, TRACKING_2))        
      {            
          t |= 0x04; // 00000100 左边数第二个        
      }        
      if (!GPIO_ReadPin(TRACKING_GPIOA, TRACKING_3))        
      {            
          t |= 0x02; // 00000010 左边数以三个        
      }        
      if (!GPIO_ReadPin(TRACKING_GPIOA, TRACKING_4))        
      {            
          t |= 0x01; // 00000001 左边数第4个        
      }        
      if (!GPIO_ReadPin(TRACKING_GPIOC, TRACKING_5))        
      {            
          t |= 0x10; // 00010000 左边数第5个        
      }        
      sensor_data = t; // 将灰度传感器的值赋值给sensor_data    
   }
}

// 串口1中断处理函数
void UART1_IRQHandler(void)
{    
    unsigned char TxRxBuffer;    
    if (USART_GetITStatus(CW_UART1, USART_IT_RC) != RESET)    
    {        
        USART_ClearITPendingBit(CW_UART1, USART_IT_RC); // 清除中断标志位        
        TxRxBuffer = USART_ReceiveData_8bit(CW_UART1);  // 将接收到的数据放入TxRxBuffer
      
      USART_RX_BUF[rxIndex] = TxRxBuffer; // 将接收到的数据放入缓冲区
      
      if (rxIndex < USART_REC_LEN - 1) // 做数据长度的限制,留一个字节用于结束字符或者溢出检测        
      {            
          // 接收到的字符包含 \n 或者 \r 结束接收            
          if (USART_RX_BUF[rxIndex - 1] == '\n' || USART_RX_BUF[rxIndex - 1] == '\r')            
          {                
              USART_RX_BUF[rxIndex] = '\0'; // 在最后一个字节加上空字符,表示字符串结束            
          }            
          else            
          {                
              rxIndex++;            
          }        
      }        
      rxIndex = 0; // 清除数据标志        
      flag = 1;    // 清除    
  }
}

来源:CW32生态社区

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

围观 8

例程资料链接如下:

BD网盘链接:

https://pan.baidu.com/s/1uA4Rn-DjOeddqIz0f0WuEw 

提取码:naap

一、简介 

L9110风扇模块是一种常见的电机驱动模块,可以用于控制小型直流风扇的转动,常被用于:

(1) 电子设备散热:将L9110风扇模块连接到需要散热的电子设备上,通过控制风扇的转速来提高设备的散热效果,保持设备的正常工作温度。

(2) DIY电子项目:L9110风扇模块是制作各种DIY电子项目的理想选择。通过将其与微控制器板结合使用,可以构建自己的智能风扇、温度控制系统等。这为爱好者提供了灵活性和创造力的发挥空间。

(3) 模型制作:L9110风扇模块也可以在模型制作领域中找到应用。通过将风扇模块嵌入模型中,并通过控制模块来改变风扇的速度和转向,可以增加模型的真实感和互动性。

2.本实验用到了CW32F030C8T6小蓝板、L9110风扇模块、LED交通信号灯模块、轻触微动立式按键开关及Keil5开发环境。 

1.png

2.png

 风扇三档转速调节系统

二、风扇三档转速调节系统说明

(1)L9110风扇模块

 3.png

L9110风扇模块,可控制正反转,具有安装孔,可以吹灭20cm外的打火机或蜡烛火焰,经常被用于灭火机器人之上。

【连线】:VCC连5V,GND连GND,INA连PA0,INB连PA1

(2)LED交通信号灯模块

 4.png

【连线】:GND连GND,R连PC13,Y连PC14,G连PC15

(3)轻触微动立式按键开关

 5.png

【连线】:VCC连+3.3V,GND连GND,OUT接PB9

三、核心代码

L9110.c:
#include "L9110.h"
#include "GTIM.h"

void L9110_GPIO_Init()      //INA接PA0,INB接PA1
{  
    __RCC_GPIOA_CLK_ENABLE();   
    GPIO_InitTypeDef GPIO_InitStruct;  
    GPIO_InitStruct.IT = GPIO_IT_NONE;   
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出模式  
    GPIO_InitStruct.Pins = GPIO_PIN_0|GPIO_PIN_1;  
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;  
    GPIO_Init(CW_GPIOA, &GPIO_InitStruct);   
    PA00_AFx_GTIM2CH1();  //PA0引脚复用为GTIM通道1  
    PA01_AFx_GTIM2CH2();  //PA1引脚复用为GTIM通道2
}

void Turn_around(int16_t value)  //风扇转动函数
{  
    if(value>0)  
    {    
        GTIM_SetCompare1(CW_GTIM2,value); //设置CRR1的值为value    
        GTIM_SetCompare2(CW_GTIM2,0);  
    }  
    else  
    {    
        GTIM_SetCompare1(CW_GTIM2,0);    
        GTIM_SetCompare2(CW_GTIM2,-value);//设置CRR2的为value  
    }
}

GTIM.c:
#include "GTIM.h"

void GTIM2_Init(void) //输出PWM到INA和INB引脚
{  
    RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_GTIM2,ENABLE);  //使能APB外设时钟   
    
    GTIM_InitTypeDef GTIM_Initstruct;  
    GTIM_Initstruct.Mode = GTIM_MODE_TIME;  //工作模式-->定时器模式 
    GTIM_Initstruct.OneShotMode = GTIM_COUNT_CONTINUE;//连续计数模式  
    GTIM_Initstruct.ToggleOutState = DISABLE;  //电平反转失能  
    GTIM_Initstruct.Prescaler = BTIM_PRS_DIV64;  //预分频  
    GTIM_Initstruct.ReloadValue =1000-1;//计数重载周期,16bit自动重载寄存器ARR,ARR的值最大为65535  
    GTIM_TimeBaseInit(CW_GTIM2,&GTIM_Initstruct);  
    //定时时长=预分频/计数器时钟源频率*(计数重载周期+1),即T=64/64000000*1000s=1ms  
    GTIM_OCInit(CW_GTIM2,GTIM_CHANNEL1,GTIM_OC_OUTPUT_PWM_LOW);//向GTIMx_CCMR寄存器中的 CCyM 位写入0xF  GTIM_OCInit(CW_GTIM2,GTIM_CHANNEL2,GTIM_OC_OUTPUT_PWM_LOW);  
    //当 GTIM2_CNT <= GTIM2_CCR1(GTIM2_CCR2)时,CH1(CH2)通道输出高电平,否则输出低电平  
    GTIM_Cmd(CW_GTIM2,ENABLE); //GTIM2使能   
    
    GTIM_SetCompare1(CW_GTIM2,0);   
    GTIM_SetCompare2(CW_GTIM2,0);  
    //GTIM2_CCR1(GTIM2_CCR2)中的比较值设为0,CH1(CH2) 通道输出保持为低电平
}
main.c
#include "main.h"
#include "LED.h"
#include "L9110.h"
#include "GTIM.h"
#include "Key.h"

int main()
{  
    LED_Init();       //三个LED灯用来指示风扇转动状态  
    L9110_GPIO_Init();//L9110风扇模块引脚初始化配置  
    Key_GPIO_Init();  //轻触微动立式按键开关用来进行三档转速调节  
    GTIM2_Init();     //输出PWM到INA,INB引脚  w
    hile(1)  
    {    
        Key_Scan();     //扫描按键并执行相应功能    
        LED_Indicator();//指示灯  
    }
}

四、效果演示+说明

(1)系统上电处于0档,风扇不转,红色LED灯点亮

 6.png

(2)第一次按下按键开关,系统设置为正向一档,风扇满占空比旋转,风力达到最大,同时红灯熄灭,黄灯点亮,代表风扇顺时针旋转。此后第二次、第三次按下开关,转速依次下降,第四次按下开关,系统回到0档

7.png

(3)第五次按下按键开关,系统设置为反向一档,风扇满占空比旋转,风力达到最大,同时红灯熄灭,绿灯点亮,代表风扇逆时针旋转。此后第六次、第七次按下开关,转速依次下降,第八次按下开关,系统回到0档

8.png

来源:CW32生态社区

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

围观 26

一、简介

1.这期视频向大家介绍如何使用CW32单片机通过ESP8266连接OneNET物联网平台,发送温湿度数据到平台,并接受平台的云控制。

二、所需物料

2.本实验使用到了CW32-48F大学计划开发板、DHT11温湿度传感器模块、ESP8266WIFI模块及Keil5开发环境。

1.png

CW32-48F大学计划板

2.png

DHT11温湿度传感器模块

3.png

ESP8266WIFI模块

 4.png

ESP8266WIFI模块引脚分布

5.png

实物图

3.接线:根据原理图,把模块连接到开发板上

(1)ESP8266WIFI模块:

开发板上预留了该模块接口,通过串口向ESP8266写入指令。

6.png

(2)DHT11模块:开发板上预留了该模块接口

7.png

4.(1)MQTT协议介绍:

MQTT是一种轻量级的发布/订阅消息传输协议,常用于物联网领域。它的特点是简化和减少了网络流量,可以高效地进行数据传输。在本次应用中,我们将使用MQTT协议进行数据上传。

(2)OneNET代码介绍:

在使用OneNet平台时,我们需要使用TCP协议进行连接。首先需要设置好TCP协议的相关参数,然后通过POST方法将温湿度数据上传到OneNet平台中。在上传数据时需要使用OneNet平台提供的API接口进行数据传输。

注:#define  PROID "XXX"  //xxx为产品ID

#define ACCESS_KEY      "XXX"   //xxx为acess_key访问密钥

#define DEVICE_NAME    "XXX"  //xxx为设备名称

8.png

9.png

三、核心代码

main.c

int main(void)
{    
    unsigned short timeCount = 0;  //发送间隔变量    
    unsigned char *dataPtr = NULL;   
    
    Hardware_Init();        //初始化外围硬件   
    while(DHT11_Init())    //检测DHT11    
    Delay_ms(200);  
    ESP8266_Init();          //初始化ESP8266  
    UsartPrintf(USART_DEBUG, "Connect MQTTs Server...\r\n");  
    while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT")) //ESP8266联网    
    Delay_ms(500);  
    UsartPrintf(USART_DEBUG, "NET_OK\r\n");    
    while(OneNet_DevLink())      //接入OneNET    
    Delay_ms(500);  
    OneNET_Subscribe();     //订阅消息传输,允许接受下发指令  
    TFTShowString(0,0,"     OneNET     ");  //界面  
    TFTShowString(1,0,"  智能物联平台  ");  
    TFTShowString(3,0,"humidity:    %");  
    TFTShowString(4,0,"temperature:  C");  
    while(1)  
    {    
        if(++timeCount >= 50)                      
        {      
            DHT11_Read_Data(&temperature,&humidity);  //读取温湿度值        
            TFTShowNumber(3,10,humidity);      
            TFTShowNumber(4,12,temperature);      
            UsartPrintf(USART_DEBUG,"TEMP:%d HUMI:%d\r\n",temperature,humidity);      
            UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");      
            OneNet_SendData();        //数据上传      
            timeCount = 0;      
            ESP8266_Clear();    //清除缓存    
        }       
        
        dataPtr = ESP8266_GetIPD(0); //接收OneNET平台返回的数据    
        if(dataPtr != NULL)      
        OneNet_RevPro(dataPtr); //确认返回数据,执行下发命令     
        
        Delay_ms(10);  
    }
}

Onenet.c:

#define PROID      "3OB4R7cKCw"       //产品ID(名称)
#define ACCESS_KEY    "n7GptYNpf9U97zHTz2ltc1Pvy4GB+0MXsU1nKel9ixc="  //产品访问密钥
#define DEVICE_NAME    "111"     //设备ID(名称)
void OneNet_RevPro(unsigned char *cmd)
{  
    char *req_payload = NULL;  
    char *cmdid_topic = NULL;  
    unsigned short topic_len = 0;  
    unsigned short req_len = 0;  
    unsigned char qos = 0;  
    static unsigned short pkt_id = 0;  
    unsigned char type = 0;  
    short result = 0;  
    char *dataPtr = NULL;  
    char numBuf[10];  
    int num = 0;   
    
    type = MQTT_UnPacketRecv(cmd);  
    switch(type)  
    {    
        case MQTT_PKT_PUBLISH:                                //接收的Publish消息       
        result = MQTT_UnPacketPublish(cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id);      
        if(result == 0)      
        {        
            char *data_ptr = NULL;        
            UsartPrintf(USART_DEBUG, "topic: %s, topic_len: %d, payload: %s, payload_len: %d\r\n",  cmdid_topic, topic_len, req_payload, req_len);        
            data_ptr = strstr(cmdid_topic, "request/");                  //查找cmdid        
            if(data_ptr)        
            {          
                char topic_buf[80], cmdid[40];    
                       
                data_ptr = strchr(data_ptr, '/');          
                data_ptr++;           
                
                memcpy(cmdid, data_ptr, 36);                      //复制cmdid          
                cmdid[36] = 0;          
                snprintf(topic_buf, sizeof(topic_buf), "$sys/%s/%s/cmd/response/%s",                              PROID, DEVICE_NAME, cmdid);          
                OneNET_Publish(topic_buf, "ojbk");                    //回复命令        
            }      
        }      
        case MQTT_PKT_PUBACK:                            //发送Publish消息,平台回复的Ack          
        if(MQTT_UnPacketPublishAck(cmd) == 0)        
        UsartPrintf(USART_DEBUG, "Tips:  MQTT Publish Send OK\r\n");    
        break;    
        case MQTT_PKT_SUBACK:   
                                     //发送Subscribe消息的Ack       
        if(MQTT_UnPacketSubscribe(cmd) == 0)        
            UsartPrintf(USART_DEBUG, "Tips:  MQTT Subscribe OK\r\n");      
        else        
            UsartPrintf(USART_DEBUG, "Tips:  MQTT Subscribe Err\r\n");    
        break;    
        default:      
        result = -1;    
        break;  
    }   
    
    ESP8266_Clear();                  //清空缓存   
    
    if(result == -1)    
    return;   
    dataPtr = strchr(req_payload, ':');          //搜索':'  
    if(dataPtr != NULL)          //如果找到了  
    {    
        dataPtr++;    
        while(*dataPtr >= '0' && *dataPtr <= '9')    //判断是否是下发的命令控制数据    
        {      
            numBuf[num++] = *dataPtr++;    
        }    
        numBuf[num] = 0;    
        num = atoi((const char *)numBuf);        //转为数值形式    
        if(strstr((char *)req_payload, "light"))    //搜索"light",判断":"后面的数值进行控制    
        {      
            if(num == 1)                //控制数据如果为1,代表开      
            {        
                UsartPrintf(USART_DEBUG, "接收到1\r\n");        
                //开灯        
                PA07_SETLOW();        
                TFTShowString(5,0,"light: ON ");      
            }      
            else if(num == 0)              //控制数据如果为0,代表关      
            {        
                UsartPrintf(USART_DEBUG, "接收到0\r\n");        
                //关灯        
                PA07_SETHIGH();        
                TFTShowString(5,0,"light: OFF");      
            }    
        }  
    }  
    if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH)  
    {    
        MQTT_FreeBuffer(cmdid_topic);    
        MQTT_FreeBuffer(req_payload);  
    }
}

来源:CW32生态社区

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

围观 13

例程资料链接如下(群文件也可下载):

BD网盘链接:

链接:https://pan.baidu.com/s/1TsDHhXUvooMH_eLBH0h08Q

提取码:sfrv

一、简介

1.MAX4466是一款低噪声、高增益的放大器模块。该模块采用了集成放大器芯片,能够在低电压下提供高增益。它的输入阻抗较高,能够与多种信号源(例如麦克风、传感器)实现良好的匹配。同时,MAX4466还具备很低的噪声水平,能够有效地提取和放大微弱的信号,提高系统的灵敏度。MAX4466模块的应用场景包括但不限于以下几个方面:

音频处理:可以作为音频信号的前置放大器,将低电平的音频信号放大到适合后续处理的水平,如音乐播放、语音识别、语音通信等。声音检测与分析:结合麦克风等音频传感器,可以实现声音的检测、分析和识别,如声音传感器、语音识别设备等。无线通信:可以用于接收无线通信模块的输入信号,对其进行放大,以提高通信距离和信号质量。

二、所需物料

本实验使用到了CW32f030c8小蓝板、MAX4466模块、LED交通信号灯模块、0.96寸OLED显示屏、Keil5开发环境及VOFA+上位机软件。

1.png

CW32F030C8小蓝板

2.png

MAX4466模块

3.png

实物(俯视)

4.png

实物(正视)

【单片机与MAX4466连线】:3.3V---VCC

GND---GND

PA0---OUT

【单片机与OLED屏连线】: GND---GND  

3.3V--VDD  

PB8--SCK  

PB9--SDA

【单片机与LED灯连线】:  GND--GND

PC15--R  

PC14--Y  

PC13--G

三、核心代码

ADC.c:
#include "ADC.h"
#include "main.h"
#include "delay.h"

void ADC_Configuration(void) 
{   
    ADC_SingleChTypeDef ADC_SingleInitStruct; 
     
    __RCC_ADC_CLK_ENABLE();    // ADC时钟使能  
    __RCC_GPIOA_CLK_ENABLE();  //GPIOA使能  
    PA00_ANALOG_ENABLE();  
    ADC_SingleInitStruct.ADC_Chmux = ADC_ExInputCH0;                //PA00 通道0  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_AccEn = ADC_AccDisable;   //转换结果累加不使能  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_Align = ADC_AlignRight;   //ADC转换结果右对齐  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_ClkDiv = ADC_Clk_Div16;   //PCLK    
    ADC_SingleInitStruct.ADC_InitStruct.ADC_DMAEn = ADC_DmaDisable;   //关闭DMA传输  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_InBufEn = ADC_BufEnable;  //开启跟随器  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_OpMode = ADC_SingleChOneMode;//单通道单次转换模式     
    ADC_SingleInitStruct.ADC_InitStruct.ADC_SampleTime = ADC_SampTime10Clk; //10个ADC时钟周期  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_TsEn = ADC_TsDisable;    //内置温度传感器禁用  
    ADC_SingleInitStruct.ADC_InitStruct.ADC_VrefSel = ADC_Vref_VDDA; //VDDA参考电压 
   
   ADC_SingleChOneModeCfg(&ADC_SingleInitStruct);                  //开始转换  
   ADC_Enable();                                                   // 使能ADC   
   
   ADC_SoftwareStartConvCmd(ENABLE);                                //转换使能
}

uint16_t Get_Data(void) //ADC数据采集
{  
    unsigned int temp_dat_adc = 0;   
    
    ADC_SoftwareStartConvCmd(ENABLE);       //开始转换  
    while(ADC_GetITStatus(ADC_IT_EOC))  
    {    
        ADC_ClearITPendingBit(ADC_IT_EOC);    //清除标志位        
        temp_dat_adc=ADC_GetConversionValue();//电压采集      
    }  
    return   temp_dat_adc;}

uint16_t Cal_Average_Data(void)
{  
    float dat;  
    uint8_t i=0;  
    for(i=0;i<50;i++)   //连续采集50次ADC的值  
    {    
        dat+=Get_Data();  //累加    
        Delay_ms(1);  
    }  
    return dat/50;      //返回平均值
}
main.c:
int main()  
{  
    uint16_t temp;  
    LED_Init();  //LED灯初始化  
    OLED_Init(); //OELD屏初始化  
    UART_Init(); //串口初始化  
    ADC_Configuration(); //ADC配置  
    OLED_ShowString(1,1,"present:");   //提示字符串  
    OLED_ShowString(2,1,"record_max:");  
    while(1)  
    {    
        temp=Cal_Average_Data();  //获取ADC数值累加后的平均值    
        printf("%d\n",temp);   //通过串口借助VOFA+软件打印波形图    
        LED_Indicator(temp);    //LED灯指示    
        Delay_ms(100);     
    }
}

四、VOFA+软件简易使用说明

5.png

6.png

7.png

①配置协议与连接:数据引擎选择”FireWater”,(注意:在程序中使用printf函数时,必须在%d后面加上\n才能在FireWater模式下被上位机正确识别),数据接口选择”串口”,正确选择端口号和配置波特率;

②在控件中找到波形图,拖拽到主窗口中,选择整窗口填充;

8.png

9.png

④右击窗口选择Y轴中的All打开Y轴数据显示;

⑤在图形种类中(默认)选择波形图;

10.png

⑥点击左上角灰黑色圆圈打开串口进行通信,看到圆圈变蓝并且闪烁代表通信正常,之后可以像调节示波器显示一样通过鼠标滚轮手动将波形调整到合适的显示范围,也可以点击Auto一键调整波形显示范围。

软件官网下载地址:https://www.vofa.plus/downloads/

五、效果演示

11.png

正常音量   12.png

正常音量波形图

13.png   

较大音量

14.png 较大音量波形图

15.png

过大音量
16.png

过大音量波形图

来源:CW32生态社区

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

围观 17

相关文章:

【CW32学习笔记】单片机启动&库函数构成

【CW32学习笔记】看手册配置时钟树

我们在前两节讲解了单片机启动到时钟树配置的内容,到此为止,单片机已经能开发别的功能并使用了,但这里我插入一个笔者个人觉得很重要的章节来介绍一个内核外设——滴答定时器(System Tick)。

根据cortex-M0+内核手册的介绍,这是一个24位倒计时定时器,它拥有4个可以访问的寄存器,

1.png

这个定时器和一般的定时器用法没什么区别,他没有高级定时器的功能,但是由于是内核白送的定时器,所以经常用于单片机的心跳时钟。

值得注意的是,滴答定时器是一个不可修改计数方式的定时器,他只能向下计数,查阅寄存器定义之后,进行如下代码的初始化操作,即可实现1ms定时并开启定时器中断。

2.png

开启定时器并打开中断之后,定时器就能正常工作,并且会正常进入其对应的中断服务函数,中断服务函数的名字可以直接在启动文件中找到(还记得第一节讲的中断向量表吗?)。

3.png

一般情况下,芯片厂商不会主动提供滴答定时器的中断服务函数接口,也就是xxxxx_it.c文件中不会出现此中断服务函数的名字(CW32的库会提供一个参考stm32 hal库的固件库,但是我觉得写的不符合我的风格,索性自己写了一个滴答定时器的文件),任何时候,只需要有这么个同名函数存在于工程文件中,该中断服务函数就能被正常调用并执行,例如这样:

4.png

实际上,任何中断服务函数都可以用这种办法来重写一个自己的,只是大部分时候官方都已经提供了良好的固件库,也就不需要我们手动重写了。

这里编写了一个测试函数来测试滴答定时器是否正常工作,实际上是使用延时函数来验证的:

5.png

那么结果当然是正常工作的!

在这里给一些建议,上手一款新的芯片的时候,完全可以直接用滴答定时器点灯来测试和上手。

总结:

1、滴答定时器是内核外设,芯片手册不会记录它的用法,内核手册才会有它的用法。

2、滴答定时器可以作为整个程序的心跳时钟,非常常用。

来源:CW32生态社区

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

围观 17

例程资料链接如下(群文件也可下载):

BD网盘链接:

https://pan.baidu.com/s/1lM3s3uZu4iEsKWiVAFFxbg 

提取码:oqe6

一、简介

1. MPU6050是一种常用的六轴姿态传感器模块,结合了三轴陀螺仪和三轴加速度计,以及一个可扩展的数字运动处理器DMP(Digital Motion Processor),可用I2C接口连接一个第三方的数字传感器,比如磁力计。MPU6050 对陀螺仪和加速度计分别用了三个16 位的ADC(0~65535),将其测量的模拟量转化为可输出的数字量。为了精确跟踪快速和慢速的运动,传感器的测量范围都是用户可控的,陀螺仪可测范围为±250,±500,±1000,±2000°/秒(dps),加速度计可测范围为±2,±4,±8,±16g。并有可编程的低通滤波器。MPU6050模块的应用场景非常广泛,包括但不限于以下几个领域:

(1)姿态感知与控制:通过读取陀螺仪和加速度计的数据,可以实时获取物体的姿态信息,如倾斜角度、旋转角度等。这在飞行器、机器人、无人车等项目中非常常见,用于实现姿态感知和控制。

(2)运动跟踪与手势识别:MPU6050可以用于捕捉人体运动轨迹,如手部的姿态和手势,从而实现运动跟踪、手势识别、虚拟现实交互等应用。

(3)震动检测与防抖:结合加速度计,MPU6050可以检测到物体的震动和冲击,用于防抖技术、硬盘保护、运动检测等。

(4)步态分析与健康监测:MPU6050可以用于分析人体的步态特征和动作,用于健康监测、运动分析、姿势校正等。

二、所需物料+寄存器说明

.本实验使用到了CW32F030C8小蓝板、GY-521模块、0.96寸OLED显示屏Keil5开发环境

1.png

CW32F030C8小蓝板

2.png   

GY-521模块

   3.png

实物展示

【GY-521模块与单片机连线】:VCC<-->+3.3V

GND<-->GND

SCL<-->PB5

SDA<-->PB4

【OLED显示屏与单片机连线】:VCC<-->+3.3V

GND<-->GND

SCL<-->PA1

SDA<-->PA2

注:SCL和 SDA是连接MCU的 IIC接口,MCU通过这个IIC 接口来控制MPU6050,另外还有一个 IIC 接口: XCL和XDA ,这个接口可用来连外部从设备比如磁力计,这样就可以组成一个九轴传感器。AD0是MPU6050的地址控制引脚,该引脚控制的是IIC 地址的最低位。MPU6050的默认IIC地址是:0X68,如果AD0接VDD,则是0X69。需要注意的是:这里的地址0x68(110 1000)和0x69(110 1001)是不包含最低位的7位数据,通常最低位用于表示IIC主机的读取数据/写数据模式。如默认情况下对MPU6050进行写操作,则发送地址0xD0(1101 0000),读操作则发送地址0xD1(1101 0001)。

寄存器说明:

 4.png

该寄存器是配置陀螺仪输出速率的分频器,用于为MPU-6050生成采样速率。这里有个公式:采样频率=陀螺仪输出频率/(1+采样分频数)。当 DLPF(数字低通滤波器,见寄存器Configuration)禁用时,陀螺仪输出频率为8kHz;当 DLPF 使能,陀螺仪输出频率=1KHz。 5.png

该寄存器为陀螺仪和加速度计配置外部帧同步(FSYNC) 管脚的采样和数字低通滤波(DLPF)设置。其中,数字低通滤波器DLPF由DLPF_CFG配置。根据下表所示的DLPF_CFG值对加速度计和陀螺仪进行滤波。

 6.png

FS为陀螺仪输出频率。SMPLRT_DIV由预设定的采样频率根据上述的公式计算得出。一般情况下,DPLF滤波频率为采样频率的一半,如设定采样频率为50Hz,由表可知当FS为1kHz,SMPLRT_DIV的值为1000/50-1=19。

6.png 

该寄存器是用来触发陀螺仪自检和配置陀螺仪的满量程范围。其中,XG_ST、YG_ST、ZG_ST分别用来设置陀螺仪X轴、Y轴、Z轴自检,置0则不触发自检。FS_SEL[1:0]用于设置陀螺仪的满量程,如下表:

 7.png

我们一般设置为3,即满量程为±2000°/s

8.png

该寄存器是用来触发加速度计自检和配置加速度计的满量程范围。同时这个寄存器也可以用于配置数字高通滤波器(DHPF)。其中,XA_ST、YA_ST、ZA_ST分别用来设置加速度计X轴、Y轴、Z轴自检,置0则不触发自检。AFS_SEL[1:0]用于选择加速度计的满量程范围,如下表:

 9.png

我们一般设置为0,即满量程为±2g

 10.png

ACCEL_XOUT :由 2部分组成的 16位数值存储最近X 轴加速度计的测量值。ACCEL_YOUT :由 2部分组成的 16位数值存储最近Y 轴加速度计的测量值。ACCEL_ZOUT :由 2部分组成的 16位数值存储最近Z 轴加速度计的测量值。

以ACCEL_XOUT为例,若倍率设定为2g,则意味着ACC_X取最小值-32768时,当前加速度为沿X轴正方向2倍的重力加速度;若设定为4g,取-32768时表示沿X轴正方向4倍的重力加速度,以此类推。显然,倍率越低精度越好,倍率越高表示的范围越大,这要根据具体的应用来设定。以ACC_X为例,若当前设定的加速度倍率为4g,那么将ACC_X读数换算为加速度的公式为:

11.png

g可取当地重力加速度。

12.png

该寄存器存储最近加陀螺仪的测量值,构成与加速度计测量值寄存器相同,不做赘述。

以GYR_X为例,若倍率设定为250度/秒,则意味着GYR取正最大值32768时,当前角速度为顺时针250度/秒;若设定为500度/秒,取32768时表示当前角速度为顺时针500度/秒。显然,倍率越低精度越好,倍率越高表示的范围越大。以GYR_X为例,若当前设定的角速度倍率为1000度/秒,那么将GRY_X读数换算为角速度(顺时针)的公式为:

 13.png

14.png

该寄存器允许用户配置电源模式和时钟源,还提供了复位整个设备和禁用温度传感器的位。当置SLEEP位为1时,MPU-60X0 可以进入低功耗睡眠模式。该寄存器的最低三位用于设置系统的时钟源选择,默认值是0(内部8M RC振荡),不过一般设置为1,即选择x轴陀螺仪PLL作为时钟源,以获得更高精度的时钟。DEVICE_RESET该位置 1,重启内部寄存器到默认值。复位完成后该位自动清0。TEMP_DIS该位置 1,禁用温度传感器。

三、核心代码

main.c:
#include "main.h"
#include "OLED.h"
#include "GY_521.h"
#include "MYI2C.h"
#include "Delay.h"    
typedef struct
{  
    int16_t AX;  
    int16_t AY;  
    int16_t AZ;  
}MPU6050_Adata;  //MPU6050加速度计三轴数据

typedef struct
{  
    int16_t GX;  
    int16_t GY;  
    int16_t GZ;  
}MPU6050_Gdata;  //MPU6050陀螺仪三轴数据

MPU6050_Adata Adata;  //结构体变量
MPU6050_Gdata Gdata;

void GY_521_Init(void)  //GY-521初始化
{  
    GY521_GPIO_Init();  //GPIO初始化  
    //解除睡眠,失能温度传感器,选择X轴的陀螺仪时钟  
    WriteData(GY521_ADDR, MPU6050_PWR_MGMT_1, 0x09);   
    WriteData(GY521_ADDR, MPU6050_CONFIG, 0x06); //低通滤波  
    WriteData(GY521_ADDR, MPU6050_SMPRT_DIV, 0x09); //1KHz十分频为100Hz  
    WriteData(GY521_ADDR, MPU6050_GYRO_CONFIG, 0x18);//陀螺仪最大量程  
    WriteData(GY521_ADDR, MPU6050_ACCEL_CONFIG, 0x18);//加速度计最大量程
}

void MPU6050_GetData()  //获取MPU6050六轴数据
{  
    uint8_t MPU6050_Raw_Data[14]={0};  
    //以MPU6050_ACCEL_XOUT_H为起始地址,连续读取14字节的数据  
    ReadData(GY521_ADDR,MPU6050_ACCEL_XOUT_H,MPU6050_Raw_Data,14);  
    //数据处理      
    Adata.AX=(MPU6050_Raw_Data[0]<<8)|MPU6050_Raw_Data[1];  
    Adata.AY=(MPU6050_Raw_Data[2]<<8)|MPU6050_Raw_Data[3];  
    Adata.AZ=(MPU6050_Raw_Data[4]<<8)|MPU6050_Raw_Data[5];  
    Gdata.GX=(MPU6050_Raw_Data[8]<<8)|MPU6050_Raw_Data[9];  
    Gdata.GY=(MPU6050_Raw_Data[10]<<8)|MPU6050_Raw_Data[11];  
    Gdata.GZ=(MPU6050_Raw_Data[12]<<8)|MPU6050_Raw_Data[13];
}

int main()
{  
    OLED_Init();   //OLED初始化  
    GY_521_Init(); //GY-521初始化  
    OLED_ShowString(1,1,"A:      G:");//提示:左列显示加速度计数据;右列显示陀螺仪数据  
    while(1)  
    {    
        MPU6050_GetData(); //获取六轴数据    
        OLED_ShowSignedNum(2,1,Adata.AX,5);    
        OLED_ShowSignedNum(3,1,Adata.AY,5);    
        OLED_ShowSignedNum(4,1,Adata.AZ,5);     
        
        OLED_ShowSignedNum(2,9,Gdata.GX,5);    
        OLED_ShowSignedNum(3,9,Gdata.GY,5);    
        OLED_ShowSignedNum(4,9,Gdata.GZ,5);    
        Delay_ms(100); //延时刷新  
    }
}

四、效果演示

15.png

平放

 16.png

向下倾斜

 17.png 

左倾斜向

18.png 

直立

读到的原始数据还不能直接使用,要转化成四元数,欧拉角后,获得器件的姿态角才有用,而 MPU6050 自带了数字运动处理器,即 DMP,并且,InvenSense 提供了一个 MPU6050 的嵌入式运动驱动库,结合 MPU6050 的 DMP,可以将我们的原始数据,直接转换成四元数输出,而得到四元数之后,就可以很方便的计算出欧拉角,从而得到yaw、roll和pitch。

来源:CW32生态社区

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

围观 55

页面

订阅 RSS - CW32