STM32学习笔记:gps两种解码的方式

发布者:MysticalSoul最新更新时间:2017-09-27 来源: eefocus关键字:STM32  gps  解码 手机看文章 扫描二维码
随时随地手机看文章

做为现在的物联网行业,手持设备中,缺少不了的就是GPS定位功能。GPS模块和STM32的串口进行通信,将GPS的数据发送给M3的串口,由M3进行GPS协议的解码。解析出来后保存在响应的结构体中。在进行显示。 
这里分别介绍2中解析协议的方法,第一种就是自己写解析协议函数,第二种便是采用别人写好的GPS解析协议库:NMEALIB库,将这个库移植到M3中,直接调用API函数,就可以解析出GPS信息,同样的也保存在一个结构体中。 
下面分析一下这两种解析协议的算法,第一种,采用的是正点原子写的GPS解析算法(感谢原子哥)

//从buf里面得到第cx个逗号所在的位置//返回值:0~0XFE,代表逗号所在位置的偏移.//       0XFF,代表不存在第cx个逗号                             u8 NMEA_Comma_Pos(u8 *buf,u8 cx)
{               
    u8 *p=buf;    while(cx)
    {        
        if(*buf=='*'||*buf<' '||*buf>'z')return 0XFF;//遇到'*'或者非法字符,则不存在第cx个逗号
        if(*buf==',')cx--;
        buf++;
    }    return buf-p;   //返回差值,}1234567891011121314

从GPS中得到的一串数据是这样的:GPRMC,083559.00,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A∗57因此,我们可以调用这个函数,得到第几个逗号所距离第一个字符的位置,例如:NMEACommaPos(buf,2),我们的到的是,第二个逗号距离的位置,也就是17

//m^n函数//返回值:m^n次方.u32 NMEA_Pow(u8 m,u8 n)
{    u32 result=1;    
    while(n--)result*=m;    
    return result;
}12345678

这个就不用多说了,都看的懂,

//str转换为数字,以','或者'*'结束//buf:数字存储区//dx:小数点位数,返回给调用函数//返回值:转换后的数值int NMEA_Str2num(u8 *buf,u8*dx)
{    u8 *p=buf;    u32 ires=0,fres=0;    u8 ilen=0,flen=0,i;    u8 mask=0;    int res;    while(1) //得到整数和小数的长度
    {        if(*p=='-'){mask|=0X02;p++;}//是负数
        if(*p==','||(*p=='*'))break;//遇到结束了
        if(*p=='.'){mask|=0X01;p++;}//遇到小数点了
        else if(*p>'9'||(*p<'0'))   //有非法字符
        {   
            ilen=0;
            flen=0;            break;
        }   
        if(mask&0X01)flen++;        else ilen++;
        p++;
    }    if(mask&0X02)buf++; //去掉负号
    for(i=0;i5)flen=5;   //最多取5位小数
    *dx=flen;           //小数点位数
    for(i=0;i

这个函数便是将两个逗号之间的字符串数字,变成整数,既将字符串“235”变成int(整型)数字,235

//分析GPGSV信息//gpsx:nmea信息结构体//buf:接收到的GPS数据缓冲区首地址void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf)
{    u8 *p,*p1,dx;    u8 len,i,j,slx=0;    u8 posx;     
    p=buf;
    p1=(u8*)strstr((const char *)p,"$GPGSV");//strstr判断$GPGSV是否是p数组的子串,是则返回$GPGSV中首先出现的地址,
    len=p1[7]-'0';                              //得到GPGSV的条数,p1[7]表示,后面的第一个字符。
    posx=NMEA_Comma_Pos(p1,3);                  //得到可见卫星总数,既将‘,’后面的字符里第一个字符的差值的到。
    if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx);//p1+posx 得到可见卫星总数的指针,
    for(i=0;islmsg[slx].num=NMEA_Str2num(p1+posx,&dx);   //得到卫星编号
            else break; 
            posx=NMEA_Comma_Pos(p1,5+j*4);            if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角 
            else break;
            posx=NMEA_Comma_Pos(p1,6+j*4);            if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
            else break; 
            posx=NMEA_Comma_Pos(p1,7+j*4);            if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx);    //得到卫星信噪比
            else break;
            slx++;     
        }   
        p=p1+1;//切换到下一个GPGSV信息
    }   
}1234567891011121314151617181920212223242526272829303132333435

这个便是解析GPGSV信息,GPGSV协议如下: 
这里写图片描述

//分析GPGGA信息//gpsx:nmea信息结构体//buf:接收到的GPS数据缓冲区首地址void NMEA_GPGGA_Analysis(nmea_msg *gpsx,u8 *buf)
{    u8 *p1,dx;           
    u8 posx;    
    p1=(u8*)strstr((const char *)buf,"$GPGGA");
    posx=NMEA_Comma_Pos(p1,6);                              //得到GPS状态
    if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx);   
    posx=NMEA_Comma_Pos(p1,7);                              //得到用于定位的卫星数
    if(posx!=0XFF)gpsx->posslnum=NMEA_Str2num(p1+posx,&dx); 
    posx=NMEA_Comma_Pos(p1,9);                              //得到海拔高度
    if(posx!=0XFF)gpsx->altitude=NMEA_Str2num(p1+posx,&dx);  
}123456789101112131415

这个是解析GPGGA信息,GPGGA协议如下: 
这里写图片描述

//分析GPGSA信息//gpsx:nmea信息结构体//buf:接收到的GPS数据缓冲区首地址void NMEA_GPGSA_Analysis(nmea_msg *gpsx,u8 *buf)
{    u8 *p1,dx;           
    u8 posx; 
    u8 i;   
    p1=(u8*)strstr((const char *)buf,"$GPGSA");
    posx=NMEA_Comma_Pos(p1,2);                              //得到定位类型
    if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx);  
    for(i=0;i<12;i++)                                       //得到定位卫星编号
    {
        posx=NMEA_Comma_Pos(p1,3+i);                     
        if(posx!=0XFF)gpsx->possl[i]=NMEA_Str2num(p1+posx,&dx);        else break; 
    }                 
    posx=NMEA_Comma_Pos(p1,15);                             //得到PDOP位置精度因子
    if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx);  
    posx=NMEA_Comma_Pos(p1,16);                             //得到HDOP位置精度因子
    if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx);  
    posx=NMEA_Comma_Pos(p1,17);                             //得到VDOP位置精度因子
    if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx);  
}123456789101112131415161718192021222324

这个是解析GPGSA信息,GPGSA协议定义如下: 
这里写图片描述 
这里写图片描述 
接下来就是我们通常要用到的一个协议了:GPRMC信息

//分析GPRMC信息//gpsx:nmea信息结构体//buf:接收到的GPS数据缓冲区首地址void NMEA_GPRMC_Analysis(nmea_msg *gpsx,u8 *buf)
{
    u8 *p1,dx;           
    u8 posx;     
    u32 temp;      
    float rs;  
    p1=(u8*)strstr((const char *)buf,"GPRMC");//"$GPRMC",经常有&和GPRMC分开的情况,故只判断GPRMC.
    posx=NMEA_Comma_Pos(p1,1);                              //得到UTC时间
    if(posx!=0XFF)
    {
        temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx);     //得到UTC时间,去掉ms
        gpsx->utc.hour=temp/10000;
        gpsx->utc.min=(temp/100)%100;
        gpsx->utc.sec=temp%100;      
    }   
    posx=NMEA_Comma_Pos(p1,3);                              //得到纬度
    if(posx!=0XFF)
    {
        temp=NMEA_Str2num(p1+posx,&dx);          
        gpsx->latitude=temp/NMEA_Pow(10,dx+2);  //得到°
        rs=temp%NMEA_Pow(10,dx+2);              //得到'        
        gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° 
    }
    posx=NMEA_Comma_Pos(p1,4);                              //南纬还是北纬 
    if(posx!=0XFF)gpsx->nshemi=*(p1+posx);                   
    posx=NMEA_Comma_Pos(p1,5);                              //得到经度
    if(posx!=0XFF)
    {                                                 
        temp=NMEA_Str2num(p1+posx,&dx);          
        gpsx->longitude=temp/NMEA_Pow(10,dx+2); //得到°
        rs=temp%NMEA_Pow(10,dx+2);              //得到'        
        gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° 
    }
    posx=NMEA_Comma_Pos(p1,6);                              //东经还是西经
    if(posx!=0XFF)gpsx->ewhemi=*(p1+posx);       
    posx=NMEA_Comma_Pos(p1,9);                              //得到UTC日期
    if(posx!=0XFF)
    {
        temp=NMEA_Str2num(p1+posx,&dx);                     //得到UTC日期
        gpsx->utc.date=temp/10000;
        gpsx->utc.month=(temp/100)%100;
        gpsx->utc.year=2000+temp%100;        
    } 
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

GPRMC协议如下: 
这里写图片描述 
这里写图片描述

//分析GPVTG信息//gpsx:nmea信息结构体//buf:接收到的GPS数据缓冲区首地址void NMEA_GPVTG_Analysis(nmea_msg *gpsx,u8 *buf)
{    u8 *p1,dx;           
    u8 posx;    
    p1=(u8*)strstr((const char *)buf,"$GPVTG");                             
    posx=NMEA_Comma_Pos(p1,7);                              //得到地面速率
    if(posx!=0XFF)
    {
        gpsx->speed=NMEA_Str2num(p1+posx,&dx);        if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx);             //确保扩大1000倍
    }
}  123456789101112131415

这个是GPVTG信息解析,协议如下: 
这里写图片描述 
到这里,一些常用的,和我们需要的都解析出来了, 
注意:这里并不是每条协议都解析,解析的是我们需要什么解析什么,,当然在实际项目中要根据自己的需求解析。 
GPS信息我们是通过串口3中断接收,将接收到的数据放在一个BUF中,

//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到//任何数据,则表示此次接收完毕.//接收到的数据状态//[15]:0,没有接收到数据;1,接收到了一批数据.//[14:0]:接收到的数据长度vu16 USART3_RX_STA=0;       


void USART3_IRQHandler(void)
{
    u8 res;       
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
    {    
        res =USART_ReceiveData(USART3);      
        if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
        { 
            if(USART3_RX_STA

USART3_RX_STA是原子自己定义的一个最高位标志位,当数据接收完成时,USART3_RX_STA|=1<<15 
将最高位标志位置1, 
这里便是定义了解析后数据保存的结构体:

//GPS NMEA-0183协议重要参数结构体定义 //卫星信息__packed typedef struct  {                                           
    u8 num;     //卫星编号
    u8 eledeg;  //卫星仰角
    u16 azideg; //卫星方位角
    u8 sn;      //信噪比          }nmea_slmsg;  
//UTC时间信息__packed typedef struct  {                                           
    u16 year;   //年份
    u8 month;   //月份
    u8 date;    //日期
    u8 hour;    //小时
    u8 min;     //分钟
    u8 sec;     //秒钟}nmea_utc_time;        
//NMEA 0183 协议解析后数据存放结构体__packed typedef struct  {                                           
    u8 svnum;                   //可见卫星数
    nmea_slmsg slmsg[12];       //最多12颗卫星
    nmea_utc_time utc;          //UTC时间
    u32 latitude;               //纬度 分扩大100000倍,实际要除以100000
    u8 nshemi;                  //北纬/南纬,N:北纬;S:南纬                 
    u32 longitude;              //经度 分扩大100000倍,实际要除以100000
    u8 ewhemi;                  //东经/西经,E:东经;W:西经
    u8 gpssta;                  //GPS状态:0,未定位;1,非差分定位;2,差分定位;6,正在估算.                  
    u8 posslnum;                //用于定位的卫星数,0~12.
    u8 possl[12];               //用于定位的卫星编号
    u8 fixmode;                 //定位类型:1,没有定位;2,2D定位;3,3D定位
    u16 pdop;                   //位置精度因子 0~500,对应实际值0~50.0
    u16 hdop;                   //水平精度因子 0~500,对应实际值0~50.0
    u16 vdop;                   //垂直精度因子 0~500,对应实际值0~50.0 

    int altitude;               //海拔高度,放大了10倍,实际除以10.单位:0.1m     
    u16 speed;                  //地面速率,放大了1000倍,实际除以10.单位:0.001公里/小时     }nmea_msg; 12345678910111213141516171819202122232425262728293031323334353637383940

到这里,采用第一种方式解析协议已经分析完了,接下来就是采用NMEALIB库解析协议, 
了解了NMEA格式有之后,我们就可以编写相应的解码程序了,而程序员Tim (xtimor@gmail.com)提供了一个非常完善的NMEA解码库,在以下网址可以下载到:http://nmea.sourceforge.net/ ,直接使用该解码库,可以避免重复发明轮子的工作。在野火提供的GPS模块资料的“NMEA0183解码库源码”文件夹中也包含了该解码库的源码,野火提供的STM32程序就是使用该库来解码NMEA语句的。 
该解码库目前最新为0.5.3版本,它使用纯C语言编写,支持windows、winCE 、UNIX平台,支持解析GPGGA,GPGSA,GPGSV,GPRMC,GPVTG这五种语句(这五种语句已经提供足够多的GPS信息),解析得的GPS数据信息以结构体存储,附加了地理学相关功能,可支持导航等数据工作,除了解析NMEA语句,它还可以根据随机数产生NMEA语句,方便模拟。

将nmealib库中的src和include这两个文件夹复制到工程,在添加进工程中,包含编译的头文件,结果如下: 
这里写图片描述 
(这里采用的是野火所提供的例程,感谢fire) 
利用nmealib解析GPS模块的输出结果大致可以分为三步, 
第一步定义和初始化GPS信息结构体和解析载体结构体, 
第二步调用nmea_parse函数完成解析工作, 
第三步释放解析载体所占用的内存空间。 
具体的代码如下注释中包含了代码的分析:

/**
  * @brief  nmea_decode_test 解码GPS模块信息
  * @param  无
  * @retval 无
                            利用nmealib解析GPS模块的输出结果大致可以分为三步,
                                第一步定义和初始化GPS信息结构体和解析载体结构体,
                                第二步调用nmea_parse函数完成解析工作,
                                第三步释放解析载体所占用的内存空间。
*/int nmea_decode_test(void)
{

    nmeaINFO info;          //GPS解码后得到的信息
    nmeaPARSER parser;      //解码时使用的数据结构 
                                                        //nmeaPARSER是解析nmea所需要的一个结构。
    uint8_t new_parse=0;    //是否有新的解码数据标志

    nmeaTIME beiJingTime;    //北京时间 

    /* 设置用于输出调试信息的函数 */
    nmea_property()->trace_func = &trace;
    nmea_property()->error_func = &error;    /* 初始化GPS数据结构 */
    nmea_zero_INFO(&info);/*对nmeaINFO这个结构中数据进行清零操作,
                                                            使用nmea_time_now函数对其中utc时间赋一个初值,初值就是当前的系统时间,
                                                            如果没有从nmea中解析出时间信息,那么最后的结果就是你当前的系统时间。
                                                                而nmeaINFO中的sig、fix分别是定位状态和定位类型
                                                        */
        nmea_parser_init(&parser);//nmeaPARSER结构做初始化,以nmea_parser_init和nmea_parser_destroy需要成对出现。

    while(1)
    {      if(GPS_HalfTransferEnd)     /* 设置半传输完成标志位
                                                                        接收到GPS_RBUFF_SIZE一半的数据 */
      {        /* 进行nmea格式解码 */
                /*
                调用nmea_parse函数对nmea语句进行解析
                原型:
                    int nmea_parse(      
                                nmeaPARSER *parser,  
                                const char *buff, 
                                int buff_sz,  
                                nmeaINFO *info  
                            )  
                这个函数有四个参数,分别是nmeaPARSER指针,buff对应需要解析的nmea语句,buff_sz为nmea语句的长度,nmeaINFO指针
                */
        nmea_parse(&parser, (const char*)&gps_rbuff[0], HALF_GPS_RBUFF_SIZE, &info);                                    //nmeaPARSER指针,需要解析的BUFF,      串口接收缓冲区一半512/2,nmeaINFO指针

        GPS_HalfTransferEnd = 0;   //清空标志位
        new_parse = 1;             //设置解码消息标志 
      }      else if(GPS_TransferEnd)    /* 接收到另一半数据 */
      {

        nmea_parse(&parser, (const char*)&gps_rbuff[HALF_GPS_RBUFF_SIZE], HALF_GPS_RBUFF_SIZE, &info);

        GPS_TransferEnd = 0;
        new_parse =1;
      }      if(new_parse )                //有新的解码消息   
      {    
        /* 对解码后的时间进行转换,转换成北京时间 */
        GMTconvert(&info.utc,&beiJingTime,8,1);        /* 输出解码得到的信息 */
        printf("\r\n时间%d,%d,%d,%d,%d,%d\r\n", beiJingTime.year+1900, beiJingTime.mon+1,beiJingTime.day,beiJingTime.hour,beiJingTime.min,beiJingTime.sec);
        printf("\r\n纬度:%f,经度%f\r\n",info.lat,info.lon);
        printf("\r\n正在使用的卫星:%d,可见卫星:%d",info.satinfo.inuse,info.satinfo.inview);
        printf("\r\n海拔高度:%f 米 ", info.elv);
        printf("\r\n速度:%f km/h ", info.speed);
        printf("\r\n航向:%f 度", info.direction);

        new_parse = 0;
      }

    }    /* 释放GPS数据结构 */
    // nmea_parser_destroy(&parser);


    //  return 0;}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687

保存解析后的结构体: 
NMEA解码库良好的封装特性使我们无需关注更深入的内部实现,只需要再了解一下nmeaINFO数据结构即可,所有GPS解码得到的结果都存储在这个结构中

typedef struct _nmeaTIME
{    int     year;       /**< Years since 1900 */
    int     mon;        /**< Months since January - [0,11] */
    int     day;        /**< Day of the month - [1,31] */
    int     hour;       /**< Hours since midnight - [0,23] */
    int     min;        /**< Minutes after the hour - [0,59] */
    int     sec;        /**< Seconds after the minute - [0,59] */
    int     hsec;       /**< Hundredth part of second - [0,99] */} nmeaTIME;

typedef struct _nmeaINFO
{    int     smask;      /**< Mask specifying types of packages from which data have been obtained */

    nmeaTIME utc;       /**< UTC of position */

    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
    int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */

    double  PDOP;       /**< Position Dilution Of Precision */
    double  HDOP;       /**< Horizontal Dilution Of Precision */
    double  VDOP;       /**< Vertical Dilution Of Precision */

    double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
    double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
    double  speed;      /**< Speed over the ground in kilometers/hour */
    double  direction;  /**< Track angle in degrees True */
    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */

    nmeaSATINFO satinfo; /**< Satellites information */} nmeaINFO;1234567891011121314151617181920212223242526272829303132333435

结构体的具体含义, 
这里写图片描述

typedef struct _nmeaPARSER
{    void *top_node;    void *end_node;    unsigned char *buffer;    int buff_size;    int buff_use;

} nmeaPARSER;123456789

可以看到,nmeaPARSER是一个链表,在解码时,NMEA库会把输入的GPS原始数据压入到nmeaPARSER结构的链表中,便于对数据管理及解码。在使用该结构前,我们调用了nmea_parser_init函数分配动态空间,而解码结束时,调用了nmea_parser_destroy函数释放分配的空间

当然最重要的还是要:分配堆栈空间 
由于NMEA解码库在进行解码时需要动态分配较大的堆空间,所以我们需要在STM32的启动文件startup_stm32f10x_hd.s文件中对堆空间进行修改,本工程中设置的堆空间大小设置为0x0000 1000,

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

;  Heap Configuration
;     Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>; Heap_Size       EQU     0x00001000

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB12345678910111213141516171819

当然,这里也是通过串口接收数据保存在这个数组中,

/* DMA接收缓冲  */uint8_t gps_rbuff[GPS_RBUFF_SIZE];//接收缓存区51212

详情了解nmealib库的可以参考这个博客: 
http://blog.csdn.net/xukai871105/article/details/12834421 
到这里,GPS协议的解析相信你应该懂了不少,


关键字:STM32  gps  解码 引用地址:STM32学习笔记:gps两种解码的方式

上一篇:STM32学习笔记:CAN总线的过滤器
下一篇:STM32学习笔记:ESP8266模块(1)

推荐阅读最新更新时间:2024-03-16 15:38

STM32的backtrace深度讲解(cortex-m的栈布局与栈回溯的原理和方案)
1.说明 2.cortex-m上的栈布局 2.1 cortex-m上的寄存器 2.2 cortex-m上的自动压栈 2.3 cortex-m上的函数执行流程 3.cmbacktrace原理分析 3.1 问题分析 4.实际应用 5.总结 1.说明 对于一个嵌入式产品的开发流程来说,一般都需要经过如下几个阶段: 1.方案预研 2.产品功能设计 3.开发调试 4.工厂测试 5.产品上线售后 一般来说,1,2,3板子都是在开发者手上,一旦遇到bug,只要可以复现,基本上都可以排查出来,然后修复或者规避。但一旦进入到4,5阶段,产品已经成型之后,再想排查BUG就比较麻烦了。例如工厂测试阶段,有可能连续运行好几天或
[单片机]
<font color='red'>STM32</font>的backtrace深度讲解(cortex-m的栈布局与栈回溯的原理和方案)
stm32的gpio口的介绍
我最近在学stm32,想和大家分享自己的学习成果,也和大家一起学习交流。之前学习过15的库函数的套用,经过一段时间摸索,我对stm32的使用有了基础的了解。因为板子不是正点原子和野火,所以有些不同。 每个板子视频教学第一个介绍都是stm32的gipo口的介绍,这个io口跟51的io口定义全然不同,并且能配置自身频率,而且有些定义用到了结构体。而且stm32是32位的单片机,内部的32位寄存器太多,很难记住,所以建议使用库函数的办法,先学会套用,后来在更改参数或者做一些小项目的时候,对一些寄存器做一些更深入的理解。 首先我们讲一下gipo口void led_init(void) { GPIO_InitTypeDe
[单片机]
STM32学习日志——IIC控制OLED
今天学习的是OLED显示实验,OLED,即有机发光二极管,自发光,不需要背光源,被认为是下一代的平面显示器新兴应用技术。 它有两个引脚,是用来控制通信方式:BS1和BS2。因为我学的是正点原子的开发板,他的OLED配件需要40元(有四种接口方式),而淘宝的IIC接口OLED的只需要9.9,于是我就买了便宜的,这就意味着要自己研究资料和敲代码。该OLED的控制芯片是SSD1306,IIC接口的只需要4根线:VCC,GND,SDA,SCL,非常节约资源。IIC通信上一次已经讲过,这次就不重复了。 这里先讲一下SSD1306写模式,1)首先是开始状态;2)发送从机地址:0x78|(W/R),写为0,读为1;3)等待回应;4)发送控制
[单片机]
<font color='red'>STM32</font>学习日志——IIC控制OLED
解决STM32开启定时器时立即进入一次中断程序问题
配置STM32定时器时,定时器中断使能、定时器使能、清除更新中断标志位,三者不同顺序程序执行时有不同效果,具体如下: TIM_ClearITPendingBit(TIM1, TIM_IT_Update); //清除更新中断请求位 TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //使能定时器1更新中断 TIM_Cmd(TIM1, ENABLE); //启动定时器 (1)。。。。。。不会立即进入更新中断程序。 TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清除更新中断请求位 TIM_Cmd(TI
[单片机]
STM32高级定时器那些事
首先说下我使用飞、高级定时器的一些坑爹经历,由于开始高级定时器使用不当,造成有如下问题: 1、PWM输出占空比反向(这个也还能接受点) 2、程序烧进去了就不能烧第二次了,下载时候提示如下图(这个够坑爹的了) 错误而提示 仔细看提示信息说是CPU一直在复位,解决的方法是通过出厂IAP用串口擦除芯片程序。需要准备的工作是:USB转串口工具、把BOOT0拉高、使用ISPMCU擦除芯片。 3、从外部flash读取出来的图片不能够正常显示,屏幕显示的是黑色,后来发现是因为SPI1的I/O与TIM8的N通道冲突了。(由此我下决心要找到问题的原因) 通过一番搜寻和查看相关资料,发现造成上述原因是因为我对高级定时器初始化的时候漏掉了部分成员
[单片机]
<font color='red'>STM32</font>高级定时器那些事
基于STM32处理器的便携式BMP图片解码系统设计
  在现代便携式设备的应用过程中,常常需要在系统中显示一些图片,而在各种图片格式中,BMP又是最具代表性的一种图片格式。   BMP是一种与硬件设备无关的图像文件格式,使用非常广泛。它采用位映射存储格式,除了图像深度可选以外,BMP文件的图像深度可选1、4、8及24 bit.BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。   典型的BMP图像文件由3部分组成:位图文件头数据结构,它包含BMP图像文件的类型、显示内容等信息;位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息。   ARM公司作为全球32位低功耗处理器设计领域的领导者,曾经设计过很多高性能低功耗的处理器,广泛应用于各种便携式手
[安防电子]
基于<font color='red'>STM32</font>处理器的便携式BMP图片<font color='red'>解码</font>系统设计
微掌科技公司选择SiGe半导体作为导航系统GPS无线射频前端解决方案的首选供应商
双方共推参考平台,满足多媒体导航系统的小尺寸和高功效需求 微掌科技公司 (Centrality Communications, Inc.) 和SiGe半导体公司 (SiGe Semiconductor) 共同宣布,微掌科技已选择 SiGe半导体作为其全球定位系统 (GPS) 无线前端 (RF) 接收器 IC 的首选供应商。双方合作共推的首款产品是一个参考平台,可为制造商的多媒体导航系统提供完整的解决方案。 该参考平台结合了SiGe半导体的 SE4110L GPS RF 前端IC与微掌科技新Atlas III 处理器的集成式GPS基带技术。利用这一参考设计,客户可以直接在支持先进导航与多媒体服务的消费电子产品的母板上实现高性能的
[手机便携]
stm32 hal i2c 库读写sd3088时钟
前一版本的修正。 sd3008在每次通信开始0.5s做一次总线复位,不必考虑stm32的i2c Bug问题。 而且HAL库,是不是也应考虑到软件上补充这个Bug? 使用HAL_I2C_Mem_Read/Write,使得代码非常好看。模拟I2C方式,一字长蛇阵模样。 使用Freertos,读取时间、保存数据到用户SRAM,需要考虑Mutex对RTC时钟资源进行保护。 * SD3088时钟芯片 读写 * 文件 sd3088.h * http://git.oschina.net/maizhi/small-pellet-sove-control-system *作者 于 *版本 v1.1 */ #incl
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved