GCC AVR(Atmel Studio+ AVR Studio)如何在程序存储器(flash)空间存放字符串常量和使用字符串常量

2023-11-08

目录

一、program memory和data memory

二、如何将字符串变量定义到program memory(flash)

三、如何读取字符串变量

四、PSTR()

五、使用strcpy()函数将字符串常量拷贝字符串缓冲区会占用大量的data memory区空间;使用strcpy_P()函数将字符串常量拷贝到字符串缓冲区仅仅占用program memory区(flash)空间,不会占用data memory区空间。

 六、使用sprintf()函数将字符串常量打印到字符串缓冲区会占用大量的data memory区空间;使用sprintf_P()函数将字符串常量打印到字符串缓冲区仅仅占用program memory区(flash)空间,不会占用data memory区空间。

七、总结


一、program memory和data memory

        GCC AVR(Atmel Studio+ AVR Studio)默认将变量(包含普通变量、数组和字符串)定义在data memory,这个需要特别注意。

        如果程序中定义有大量的常量,在定义时,一定要在头部写上PROGMEM,还要添加头文件#include <avr/pgmspace.h>,这样,定义的常量就保存在program memory(flash)中了。否则,系统就会将变量定义到data memory区,编译时由于data memory仅有4k而会出现内存溢出的现象。
        当data memory区的变量读取program memory区的数据时,需要用库函数pgm_read_byte()进行读取。

二、如何将字符串变量定义到program memory(flash

        第一步:必须包含头文件:#include <avr/pgmspace.h>

#include <avr/pgmspace.h>

        第二步:用关键字PROGMEM定义字符串常量

PROGMEM const char flash_string[]= "Hello World.";

三、如何读取字符串变量

        当data memory区的变量去读取program memory区的数据时,需要用库函数pgm_read_byte()进行读取,下面我们编写一个入口参数为字符串常量的函数,将入口的字符串常量发送到串口1,需要用到系统提供的函数pgm_read_byte()。

#include <avr/pgmspace.h>

PROGMEM const char flash_string[]= "Hello World.";


void HMISendString_const(const char *string)
{
	uint8_t ch;
    	
	
	while (pgm_read_byte(&(*string)) != '\0')
    {
		ch = pgm_read_byte(&(*string));
        UDR1 = ch;
        string++;
    }    
}


int main(void)
{
    HMISendString_const(flash_string); 
}

四、PSTR()

        AVR提供了一个宏 PSTR(),它在头文件pgmspace.h中,它可以用于将字符串定义到program memory区(flash)。宏 PSTR()的具体定义参见下图。

         上面的程序代码可以不定义PROGMEM const char flash_string[]= "Hello World.";  而是可以直接用宏 PSTR()将字符串定义到program memory区(flash),改造后的程序如下:

#include <avr/pgmspace.h>

void HMISendString_const(const char *string)
{
	uint8_t ch;
    	
	
	while (pgm_read_byte(&(*string)) != '\0')
    {
		ch = pgm_read_byte(&(*string));
        UDR1 = ch;
        string++;
    }    
}


int main(void)
{
    HMISendString_const(PSTR("Hello World.")); 
}

五、使用strcpy()函数将字符串常量拷贝字符串缓冲区会占用大量的data memory区空间;使用strcpy_P()函数将字符串常量拷贝到字符串缓冲区仅仅占用program memory区(flash)空间,不会占用data memory区空间。

1、使用strcpy()函数拷贝字符串前,先在data memory空间定义了一个字符串缓冲区char HMI_string[255],编译程序后发现data memory空间占用了2362个字节。

 2、现在我们用库函数strcpy()编写一段程序,将字符串常量 "I am C++"拷贝到字符串缓冲区HMI_string,观察是否会占用data memory区空间。

        程序代码参见下图,编译程序后发现data memory空间目前占用了2370个字节(之前为2362个字节)。

        怎么只是在程序中调用了strcpy(HMI_string , "I am C++") ,data memory空间就多占用了8个字节呢?     

  3、现在我们用库函数strcpy()再编写一段程序,将字符串常量 "I am C#"拷贝到字符串缓冲区HMI_string,观察是否会继续占用data memory区空间。

        程序代码参见下图,编译程序后发现data memory空间目前占用了2378个字节,又比之前多占用了8个字节(之前占用了2370个字节)。

        我们发现一个规律:(1)、只要调用strcpy(HMI_string , "I am C++"),编译器发现第二个入口参数是普通的字符串"I am C++",就会在data memory空间申请8个字节的空间。(2)、只要调用strcpy(HMI_string , "I am C#"),编译器发现第二个入口参数是普通的字符串"I am C#",就会在data memory空间申请8个字节的空间。       

 4、如何将一串字符串常量拷贝到字符串缓冲区,而且还可以确保第二个入口参数不占用data memory空间呢?

      strcpy()函数是GCC AVR的头文件string.h中的函数,要想将一串字符串常量拷贝到字符串缓冲区,而且字符串拷贝函数的入口参数还不占用data memory空间,就必须要使用头文件pgmspace.h中的库函数strcpy_P,库函数strcpy_P的原型如下:

                  char *strcpy_P(char *, const char *);                 

        头文件pgmspace.h中的库函数与头文件string.h中的库函数的区别是:

        (1)、pgmspace.h中的库函数比头文件string.h中的库函数多了一个后缀  _P。

        (2)、char *strcpy_P(char *, const char *)   第二个参数是程序存储器program memory区(flash)。

        (3)、主程序调用strcpy_P(HMI_string , PSTR("I am C++"));时,第二个参数不会占用data memory空间。

        因此,要想将一串字符串常量拷贝到字符串缓冲区,而且还要让入口参数的字符串常量不占用data memory空间,就必须要使用头文件pgmspace.h中的函数char *strcpy_P(char *, const char *)   

        警告:strcpy_P()的第二个入口参数的类型是 const,因此需要在字符串常量前面添加宏PSTR(),将其定义到program memory区

                  例如:

                             strcpy_P(HMI_string , PSTR("I am C++"));

5、验证

        (1)、程序中添加 strcpy_P(HMI_string , PSTR("I am C++")); ,程序编译程序后data memory空间仍然是2362字节,可见使用头文件pgmspace.h中的库函数 strcpy_P(), 第二个参数PSTR("I am C++")不会增加data memory空间。   

         (2)、程序中再添加 strcpy_P(HMI_string , PSTR("I am C#")); ,程序编译程序后data memory空间仍然是2362字节,可见使用头文件pgmspace.h中的库函数 strcpy_P(), 第二个参数PSTR("I am C#")不会增加data memory空间。   

 六、使用sprintf()函数将字符串常量打印到字符串缓冲区会占用大量的data memory区空间;使用sprintf_P()函数将字符串常量打印到字符串缓冲区仅仅占用program memory区(flash)空间,不会占用data memory区空间。

1、使用sprintf()函数打印字符串前,编译程序后发现data memory空间占用了2362个字节。

 2、现在我们用库函数sprintf()编写一段程序,将字符串常量 "I am C++"和数值1275混合打印到字符串缓冲区HMI_string,观察是否会占用data memory区空间。

        程序代码参见下图,编译程序后发现data memory空间目前占用了2372个字节(之前为2362个字节)。

        怎么只是在程序中调用了sprintf(HMI_string , "I am C++%d" , 1278) ,data memory空间就多占用了10个字节呢?     

        我们发现一个规律:(1)、只要调用sprintf(HMI_string , "I am C++%d" , 1278) 编译器发现第二个入口参数是普通的字符串"I am C++",就会在data memory空间申请10个字节的空间。

 3、如何将一串字符串常量和数值混合打印到字符串缓冲区,而且还可以确保第二个入口参数不占用data memory空间呢?

      sprintf()函数是GCC AVR的头文件string.h中的函数,要想将一串字符串常量和数值混合打印到字符串缓冲区,而且字符串打印函数的入口参数还不占用data memory空间,就必须要使用头文件pgmspace.h中的库函数sprintf_P,库函数sprintf_P的原型如下:

                      int    sprintf_P(char *__s, const char *__fmt, ...);

    头文件pgmspace.h中的库函数与头文件string.h中的库函数的区别是:

        (1)、pgmspace.h中的库函数比头文件string.h中的库函数多了一个后缀  _P。

        (2)、 int    sprintf_P(char *__s, const char *__fmt, ...); 第二个参数是程序存储器program memory区(flash)。

        (3)、主程序调用sprintf(HMI_string , "I am C++%d" , 1278)时,第二个参数不会占用data memory空间。

          因此,要想将一串字符串常量和数值混合打印到字符串缓冲区,而且还要让入口参数的字符串常量不占用data memory空间,就必须要使用头文件pgmspace.h中的函数 sprintf_P(char *__s, const char *__fmt, ...) 

        警告:sprintf_P()的第二个入口参数的类型是 const,因此需要在字符串常量前面添加宏PSTR(),将其定义到program memory区

                  例如:

                             sprintf_P(HMI_string , PSTR("I am C++%d") , 1278);

4、验证

        (1)、程序中添加 sprintf_P(HMI_string , PSTR("I am C++%d") , 1278); ,程序编译程序后data memory空间仍然是2362字节,可见使用头文件pgmspace.h中的库函数 sprintf_P(), 第二个参数PSTR("I am C++%d")不会增加data memory空间。   

 

七、总结

1、要想定义字符串常量到program memory区,首先要添加头文件#include <avr/pgmspace.h>,

2、然后用关键字PROGMEM定义字符串常量,例如:PROGMEM const char flash_string[]= "Hello World.";

3、也可以宏定义PSTR()直接在用户函数的入口参数上进行限制,例如:HMISendString_const(PSTR("Hello World."));

4、要想将字符串常量拷贝字符串缓冲区而不占用data memory区空间,必须要使用头文件pgmspace.h中的strcpy_P(),而不能使用头文件string.h中的strcpy()。而且strcpy_P()的第二个入口参数必须要用宏PSTR()进行限定,例如:strcpy_P(HMI_string , PSTR("I am C++"));

5、要想将字符串常量和数值混合打印到字符串缓冲区而不占用data memory区空间,必须要使用头文件pgmspace.h中的sprintf_P(),而不能使用头文件string.h中的sprintf()。而且sprintf_P()的第二个入口参数必须要用宏PSTR()进行限定,例如:sprintf_P(HMI_string , PSTR("I am C++%d") , 1278);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC AVR(Atmel Studio+ AVR Studio)如何在程序存储器(flash)空间存放字符串常量和使用字符串常量 的相关文章

  • JSP

    jsp简介 1 JSP Java Server Pages 是JavaWeb服务器端的动态资源 它与html页面的作用是相同的 显示数据和获取数据 2 jsp 作为请求发起页面 例如显示表单 超链接 作为请求结束页面 例如显示数据 3 Se
  • 【华为OD机试】跳格子2【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 小明和朋友玩跳格子游戏 有 n 个连续格子组成的圆圈 每个格子有不同的分数 小朋友可以选择从任意格子起跳 但是不能跳连续的格子 不能回头跳 也不能超过一圈 给定一个代
  • go语言操作Redis详细步骤

    前言 导入开源库 操作字符串 package main import fmt github com garyburd redigo redis func main 通过 go 向 redis 写入和读取数据 1 连接到redis conn
  • TLS协议分析

    TLS协议分析 2015 09 06 本文目标 学习鉴赏TLS协议的设计 透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛 读者需要对现代密码学有清晰而系统的理解 建议花精力补足背景
  • [github项目]基于百度地图二次开发实现的车辆监管(包含车辆定位、车辆图片和方向控制,电子围栏,图形绘制等功能)前端实现(不包含后端实现)...

    前言 基于百度地图javascript版本开发 百度地图中所用的key已承诺仅用于测试 不用于商业用途 注 本文所有代码可以到github上进行下载 github地址 http map eguid cc 已经封装好的功能 基于百度地图二次开
  • Matlab Babble噪声

    问题 我们在做语音相关实验的时候可能需要用到Babble噪声 解决 可以从该链接下载babble噪声 截取我们所需要的长度 设置信噪比 进行加噪 上代码 load babble mat 导入babble文件 voicepath M5 wav

随机推荐

  • 随机生成几位字母加数字的混合字符串

    日常开发中 我们可能需要一些随机字符串做测试 可能是4位 也可能是8位 如下是一个随机生成8位字符串的工具类 可根据需要 改成自己的需要的 import java util Random public class RandomGenerat
  • mysql 设置 utc_关于时间:MySQL应该将其时区设置为UTC吗?

    跟随问题HTTPS serverfault com questions 191331 should servers have their timezone set to GMT UTC 应将神秘的时间带设置到UTC 还是应设置为服务器或PH
  • 期货开户不要孤注一掷

    一 在没有稳定盈利之前 特别是新手 尽可能少入金 建议不要超过1万 每次只做一手 因为新手没有不亏的 投的多 就意味着亏的多 持续稳定盈利再多投入 才是上策 许多新手一两周就亏几万几十万的 等明白期货的凶险 已经晚了 下单后 连续三天很纠结
  • [已解决] wget命令出现Unable to establish SSL connection.错误

    文章目录 解决 从linux上下载mysql 包时 wget https downloads mysql com archives get p 23 file mysql 5 6 46 linux glibc2 12 x86 64 tar
  • qt 中 file generation failure: unable to create the directory

    原因 不能将qt的项目工程安装到qt软件的安装目录中 如 opt 的目录中 解决 应该使用当前系统的普通用户的目录中建立项目目录 如 home chenfan QT myprojects
  • 数据分析概述和理论基础

    2018 03 26 Python开发者交流平台 什么是数据分析 数据分析 是指用适当的统计分析方法对收集来的大量数据进行分析 提取有用信息和形成结论 而对数据加以详细研究和概括总结的过程 为什么会有数据分析 随着计算机技术 互联网技术 数
  • Linux---用户的权限

    专栏 Linux 个人主页 HaiFan 本章为大家带来用户的权限的讲解 用户的权限 Linux权限的概念 权限的三类对象 权限的三种类型 权限设置chmod chown chgrp 更改权限chmod chown chgrp umask
  • Atcoder Beginner Contest 164 D

    题意 给定一个只包含数字字符且不包含 0 0 0字符的字符串 S S S 问有子串组成的十位数是 2019 2019
  • QListView的使用

    一 介绍 QListView可以用来以列表的形式展示数据 在Qt中使用model View结构来管理数据与视图的关系 model负责数据的存取 数据的交互则通过delegate来实现 二 model QT提供了一些现成的models用于处理
  • drools规则引擎初探

    1 drools是什么 Drools是为Java量身定制的基于Charles Forgy的RETE算法的规则引擎的实现 具有了OO接口的RETE 使得商业规则有了更自然的表达 Rule是什么呢 一条规则是对商业知识的编码 一条规则有 att
  • Java中Set的使用

    在Java中使用Set 可以方便地将需要的类型以集合类型保存在一个变量中 主要应用在显示列表 Set是一个不包含重复元素的 collection 更确切地讲 set 不包含满足 e1 equals e2 的元素对 e1 和 e2 并且最多包
  • 如何修改桌面的存放路径?(将桌面放到D盘或E盘)

    方法1 使用超级兔子 依次选择 魔法设置 系统 系统文件夹 桌面 就可以自定义桌面项的路径了 方法2 首先要在 开始 运行 内输入 regedit 打开注册表编辑器 然后要在 文件 下拉菜单中 的 导出 功能备份好注册表 以防万一 接着在左
  • 学习笔记——Java入门第二季

    1 1 介绍类与对象 类和对象的关系 时间万物皆对象 对象是具体的事物 是类的具体事例 类是抽象的概念 是对象的模板 new关键字是创建实例对象最重要的标志 Dog duoduo new Dog Dog lucky new Dog 这样就创
  • RabbitMQ--扩展--11--均衡负载

    RabbitMQ 扩展 11 均衡负载 1 场景 面对大量业务访问 高并发请求 可以使用高性能的服务器来提升RabbitMQ服务的负载能力 当单机容量达到极限时 可以采取集群的策略来对负载能力做进一步的提升 但这里还存在一个负载不均衡的问题
  • consul作为配置中心

    Conusl可以作为注册中心 也可以作为配置中心 作为配置中心 使用起来也很方便 大多数都是配置 Consul的安装这里不说了 主要是说明java后端怎么使用 所以本次采用windows版本的consul 引入和配置 2个文件 pom配置
  • ajax error弹框,完美解决:layui弹出层无法关闭/ajax请求成功,但是不进入success,也不进入error...

    我在使用一个叫做H ui admin的后台模板 基于layui 做一套管理系统 业务 点击按钮 出现弹出层 ajax通过接口向后台发送数据 成功后 关闭弹出层 前面都没有什么问题 就是到了关闭弹出层 真的快把我逼疯了 1 首先 我认为是la
  • IFrame和Ajax比较

    说到比较 可能我是需要把这连个东西都给大家介绍一下的 但是介于大家都已经有了很多的理解 我就简单的说了 Ajax 是指一种创建交互式网页应用的网页开发技术 主要是利用XmlHttpRequest对象 该对象在 Internet Explor
  • 网络基础知识

    网络基础概念 网络 两个设备之间 通过介质连接起来就形成网络 上网 就是连接到英特网 要想使pc机之间关联起来 要设置地址 1 IP地址 子网掩码 网关 2 MAC地址 物理地址 window键 R会跳出运行窗口 输入ncpa cpl可以调
  • UGUI ScrollRect使用(实现滑动效果)

    在工作中需要实现滑动效果 网上一番资料查询之后了解到ScrollRect组件 记录一下使用过程中遇到的问题与解决办法 先来看一下ScrollRect的属性 其中Content和Viewport非常重要 能否实现滑动效果取决于这两个属性 至于
  • GCC AVR(Atmel Studio+ AVR Studio)如何在程序存储器(flash)空间存放字符串常量和使用字符串常量

    目录 一 program memory和data memory 二 如何将字符串变量定义到program memory flash 三 如何读取字符串变量 四 PSTR 五 使用strcpy 函数将字符串常量拷贝字符串缓冲区会占用大量的da