#define SREG (*(volatile unsigned CHAR *)0x5F)

本文详细解释了在嵌入式系统编程中如何使用volatile和指针来访问固定内存地址,包括如何将地址转换为指针类型、使用volatile关键字的意义以及在不同场景下的应用。

终于理解了#define SREG (*(volatile unsigned CHAR *)0x5F) 以前看到#define SREG     (*(volatile unsigned CHAR *)0x5F) 这样的定义,总是感觉很奇怪,不知道为什么,今天终于有了一点点心得,请大虾们多多批砖~~~

    嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x5F,     第一步是要把它强制转换为指针类型 (unsigned CHAR *)0x5F,AVR的SREG是八位寄存器,所以0x5F强制转换为指向 unsigned CHAR类型。     volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变——意想不到。     第二步,对指针变量解引用,就能操作指针所指向的地址的内容了     *(volatile unsigned CHAR *)0x5F     第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯,所以#define SREG     (*(volatile unsigned CHAR *)0x5F)

     类似的,如果使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义#define RAM_ADDR      (*(volatile unsigned LONG   *)0x0000555F)      然后就可以用C语言对这个内存地址进行读写操作了      读:tmp = RAM_ADDR;      写:RAM_ADDR = 0x55;

已下是文章二

对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。

         以 #define IOPIN   (*((volatile unsigned long *) 0xE0028000))   为例:作为一个宏定义语句,define是定义一个变量或常量的伪指令。首先( volatile unsigned long * )的意思是将后面的那个地址强制转换成 volatile unsigned long * ,unsigned long * 是无符号长整形,volatile 是一个类型限定符,如const一样,当使用volatile限定时,表示这个变量是依赖系统实现的,以为着这个变量会被其他程序或者计算机硬件修改,由于地址依赖于硬件,volatile就表示他的值会依赖于硬件。

        volatile 类型是这样的,其数据确实可能在未知的情况下发生变化。比如,硬件设备的终端更改了它,现在硬件设备往往也有自己的私有内存地址,比如显存,他们一般是通过映象的方式,反映到一段特定的内存地址当中,这样,在某些条件下,程序就可以直接访问这些私有内存了。另外,比如共享的内存地址,多个程序都对它操作的时候。你的程序并不知道,这个内存何时被改变了。如果不加这个voliatile修饰,程序是利用catch当中的数据,那个可能是过时的了,加了 voliatile,就在需要用的时候,程序重新去那个地址去提取,保证是最新的。归纳起来如下:

1. volatile变量可变允许除了程序之外的比如硬件来修改他的内容   2. 访问该数据任何时候都会直接访问该地址处内容,即通过cache提高访问速度的优化被取消 

       对于((volatile unsigned long *) 0xE0028000)为随硬件需要定义的一种地址,前面加上“*”指针,为直接指向该地址,整个定义约定符号IOPIN代替,调用的时候直接对指向的地址寄存器写内容既可。这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。上述表达式拆开来分析,首先(volatile unsigned long *) 0xE0028000的意思是把0xE0028000强制转换成volatile unsigned long类型的指针,暂记为p,那么就是#define A *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。

对于(volatile unsigned char *)0x20我们再分析一下,它是由两部分组成: 1)(unsigned char *)0x20,0x20只是个值,前面加(unsigned char *)表示0x20是个地址,而且这个地址类型是unsigned char ,意思是说读写这个地址时,要写进unsigned char 的值,读出也是unsigned char 。 2)volatile,关键字volatile 确保本条指令不会因C 编译器的优化而被省略,且要求每次直接读值。例如用while((unsigned char *)0x20)时,有时系统可能不真正去读0x20的值,而是用第一次读出的值,如果这样,那这个循环可能是个死循环。用了volatile 则要求每次都去读0x20的实际值。

那么(volatile unsigned char *)0x20是一个固定的指针,是不可变的,不是变量。而char   *u则是个指针变量。 再在前面加"*":*(volatile unsigned char *)0x20则变成了变量(普通的unsigned char变量,不是指针变量),如果#define i (*(volatile unsigned char *)0x20),那么与unsigned char i是一样了,只不过前面的i的地址是固定的。

那么你的问题就可解答了,(*(volatile unsigned char *)0x20)可看作是一个普通变量,这个变量有固定的地址,指向0x20。而0x20只是个常量,不是指针更不是变量。

/* Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 Copyright (c) 2009 Michael Margolis. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method. The servos are pulsed in the background using the value most recently written using the write() method. Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached. Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four. The sequence used to sieze timers is defined in timers.h The methods are: Servo - Class for manipulating servo motors connected to Arduino pins. attach(pin ) - Attaches a servo motor to an i/o pin. attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds default min is 544, max is 2400 write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) writeMicroseconds() - Sets the servo pulse width in microseconds read() - Gets the last written servo pulse width as an angle between 0 and 180. readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) attached() - Returns true if there is a servo attached. detach() - Stops an attached servos from pulsing its i/o pin. */ #ifndef Servo_h #define Servo_h #include <inttypes.h> /* * Defines for 16 bit timers used with Servo library * * If _useTimerX is defined then TimerX is a 16 bit timer on the current board * timer16_Sequence_t enumerates the sequence that the timers should be allocated * _Nbr_16timers indicates how many 16 bit timers are available. */ // Architecture specific include #if defined(ARDUINO_ARCH_AVR) #include "avr/ServoTimers.h" #elif defined(ARDUINO_ARCH_SAM) #include "sam/ServoTimers.h" #elif defined(ARDUINO_ARCH_SAMD) #include "samd/ServoTimers.h" #elif defined(ARDUINO_ARCH_STM32F4) #include "stm32f4/ServoTimers.h" #elif defined(ARDUINO_ARCH_NRF52) #include "nrf52/ServoTimers.h" #else #error "This library only supports boards with an AVR, SAM, SAMD, NRF52 or STM32F4 processor." #endif #define Servo_VERSION 2 // software version of this library #define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo #define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached #define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds #define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer #define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER) #define INVALID_SERVO 255 // flag indicating an invalid servo index #if !defined(ARDUINO_ARCH_STM32F4) typedef struct { uint8_t nbr :6 ; // a pin number from 0 to 63 uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false } ServoPin_t ; typedef struct { ServoPin_t Pin; volatile unsigned int ticks; } servo_t; class Servo { public: Servo(); uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. void detach(); void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds void writeMicroseconds(int value); // Write pulse width in microseconds int read(); // returns current pulse width as an angle between 0 and 180 degrees int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) bool attached(); // return true if this servo is attached, otherwise false private: uint8_t servoIndex; // index into the channel data for this servo int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH }; #endif #endif Servo.h文件中是这样的该怎么修改
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值