Low Voltage Energy Storage
LFP 5-10kWh / LV
LiFePO4 BATTERY, 51.2V 100/200Ah
LFP5-10kWh/LV is the latest Wall Mounted Lithium Battery for Home Energy Storage system. It is based on lithium iron phosphate batteries and equipped with customized BMS. 6000+ high cycle times, long service life, stylish appearance design, make it popular with many customers, and suitable for daily charging and discharging application scenarios.
Low Voltage Energy Storage LFP2400/LFP5000
LFP2400, LFP5000 are hot-selling Rack Mounted Lithium Batteries provided by Sunket with our abundant experience for Home Energy Storage. It` s long life character, high energy and power density in the industry, fashionable design, easiness of installation and expansion, all reflects the real requirements of end users and strongest technical capability of Sunket.
T200/T500
Portable Power Bank
Portable power bank is the definition of a new way of life. It adopts high-safety lithium iron phosphate battery and integrates various power ports.
It is suitable for the operation of lighting, small household appliances, mobile phones, cameras, notebook computers, vehicle electrical appliances, automotive emergency start, medical emergency equipment and other products in off-grid or power failure scenarios such as indoor backup, outdoor activities, car self-driving tours, and emergency rescue.
High Voltage Energy Storage 30kW/92kWh
·Small size, high integration
·User-defined operating mode is easy to set
·Support on-grid and off-grid switching
·Installation and access points for supporting microgrid energy devices
·Comprehensive energy management, real-time dynamic operation monitoring
·AI cloud computing data processing, intelligent management and control
Solar Battery for Solar System,Home Energy Storage, Wuxi Sunket New Energy Technology Co.,Ltd , https://www.sunketsolar.com
The eighth chapter is about understanding AMetal in depth. The content of this article covers sections 8.3, the buzzer interface, and 8.4, the temperature acquisition interface.
**8.3 Buzzer Interface**
> > >
**8.3.1 Defining Interfaces**
**1. Interface Naming**
Since the object of operation is a buzzer, the interface name is prefixed with "am_buzzer_". For the buzzer, the basic operations are to turn it on and off. Corresponding interfaces can be defined as:
- `Am_buzzer_on`
- `Am_buzzer_off`
In some applications, a "click" operation is required, where the beep stops automatically after a certain time. You can define its interface name as:
- `Am_buzzer_beep`
- `Am_buzzer_beep_async`
These two interfaces are used for the buzzer to call a specified time. The difference lies in the timing of the function return. `Am_buzzer_beep` waits for the beep to finish before returning, while `Am_buzzer_beep_async` returns immediately, and the buzzer stops automatically after the specified time.
This asynchronous interface was derived from practical applications because in some scenarios, blocking the program is not desirable. Therefore, an interface like `Am_buzzer_beep_async` is necessary.
**2. Interface Parameters**
In the design of the LED universal interface, multiple LEDs may exist in a system, so a unique ID is used to distinguish them. However, for the buzzer, which has a single function and is typically a single device, there's no need for parameters like `buzzer_id`.
For the `Am_buzzer_on` and `Am_buzzer_off` interfaces, no parameters are needed:
- `Am_buzzer_on(void);`
- `Am_buzzer_off(void);`
However, for `Am_buzzer_beep` and `Am_buzzer_beep_async`, a parameter is required to specify the duration of the beep in milliseconds:
- `Am_buzzer_beep(uint32_t ms);`
- `Am_buzzer_beep_async(uint32_t ms);`
**3. Return Value**
All interfaces return a standard error number of type `int`. Based on this, the complete definition of the buzzer control interface is shown in Table 8.5.
**Table 8.5 Buzzer Universal Interface (am_buzzer.h)**
[Image: http://i.bosscdn.com/blog/15/32/33/5305-0.jpg]
The corresponding class diagram is shown in Figure 8.8.
[Image: http://i.bosscdn.com/blog/15/32/33/4628-1.jpg]
**Figure 8.8 Buzzer Interface Class Diagram**
> > >
**8.3.2 Implementing the Interface**
**1. Abstract Buzzer Device Class**
The buzzer has four general-purpose interfaces. `Am_buzzer_beep()` and `Am_buzzer_beep_async()` can be implemented based on `Am_buzzer_on()` and `Am_buzzer_off()`. The implementation of `Am_buzzer_beep()` is shown in Listing 8.24.
**Listing 8.24 Implementation of Am_buzzer_beep()**
[Image: http://i.bosscdn.com/blog/15/32/33/1007-2.jpg]
In the program, `Am_buzzer_on()` is first used to open the buzzer. If the opening is successful, a delay is used, and then the buzzer is turned off. For `Am_buzzer_beep_async()`, a software timer is used instead of a delay function. The sample program is shown in Listing 8.25.
**Sample Listing 8.25 Am_buzzer_beep_async() Sample Program**
[Image: http://i.bosscdn.com/blog/15/32/33/2145-3.jpg]
In the program, `Am_buzzer_on()` is called, and if successful, a software timer is started. After the timer expires, the callback function `__beep_timer_callback()` is called to turn off the buzzer.
The software timer must be initialized before use. The appropriate timing for initializing the timer is described later.
Since `Am_buzzer_beep()` and `Am_buzzer_beep_async()` can be implemented based on `Am_buzzer_on()` and `Am_buzzer_off()`, the core of the buzzer interface is to implement these two functions. They can be abstracted using methods similar to those for LEDs or HC595 devices.
[Image: http://i.bosscdn.com/blog/15/32/33/5136-5.jpg]
Although feasible, since on and off are symmetric operations, one method can be abstracted with a boolean parameter to distinguish between on and off.
[Image: http://i.bosscdn.com/blog/15/32/33/6408-6.jpg]
Abstract methods are often placed in a virtual function table for consistency and future extension.
[Image: http://i.bosscdn.com/blog/15/32/33/3248-7.jpg]
Similarly, the abstract method and `p_cookie` are defined together, forming an abstract buzzer device.
[Image: http://i.bosscdn.com/blog/15/32/33/3N7-8.jpg]
In the previous implementation of `Am_buzzer_beep_async()`, a software timer was used. Since the timer is related to the buzzer device, it should not be a global variable but rather part of the abstract device structure.
[Image: http://i.bosscdn.com/blog/15/32/33/3T1-9.jpg]
Abstract methods defined in abstract devices must be implemented by specific devices. The `Am_buzzer_on()` and `Am_buzzer_off()` interfaces can be implemented based on these abstract methods.
When defining the buzzer interface, since it's a single-instance device, no parameter is defined to distinguish the device. Instead, a global variable is used to point to the buzzer device. The implementation of `Am_buzzer_on()` and `Am_buzzer_off()` is detailed in Listing 8.26.
**Sample Listing 8.26 Sample Programs for Am_buzzer_on and Am_buzzer_off()**
[Image: http://i.bosscdn.com/blog/15/32/33/E06-10.jpg]
Where `__gp_buzzer_dev` is a pointer to the buzzer device, initially set to NULL. To use the buzzer properly, `__gp_buzzer_dev` must point to a valid device, requiring the `pfn_buzzer_set` abstract method to be implemented by the specific device.
To complete the assignment of `__gp_buzzer_dev`, a device registration interface is defined for registering a valid buzzer device with the system.
[Image: http://i.bosscdn.com/blog/15/32/33/G14-11.jpg]
This interface allows the user to add a buzzer device to the system without directly operating each member of the device.
The program first checks the validity of the parameter, then completes the abstract method and `p_cookie` assignment, assigns `__gp_buzzer_dev` to the valid device, and initializes the software timer in the abstract device.
It can be seen that the initialization of the software timer is completed when a buzzer device is added.
Next, a specific buzzer device is derived from the abstract device, the `pfn_buzzer_set` abstract method is implemented, and the device is added to the system using the `am_buzzer_dev_register()` interface.
For ease of reference, the contents of the buzzer device interface file (`am_buzzer_dev.h`) are shown in Listing 8.28. The corresponding class diagram is shown in Figure 8.9.
**Listing 8.28 am_buzzer_dev.h File Contents**
[Image: http://i.bosscdn.com/blog/15/32/33/G13-13.jpg]
[Image: http://i.bosscdn.com/blog/15/32/33/K22-14.jpg]
**Figure 8.9 Abstract Buzzer Device Class**
**2. Specific Buzzer Device Class**
Taking PWM output control of a buzzer as an example, the implementation of the specific device is briefly described. A specific device class is derived from the abstract device class. The class diagram is shown in Figure 8.10.
[Image: http://i.bosscdn.com/blog/15/32/33/2160-15.jpg]
[Image: http://i.bosscdn.com/blog/15/32/33/2635-16.jpg]
**Figure 8.10 Specific Buzzer Device Class**
`Am_buzzer_pwm_dev_t` is the specific device class. With this type, a specific device instance can be defined. Since the buzzer is a single-instance device, it is possible to define a device instance directly in a file without requiring the user to create a custom instance.
The type name can be modified to start with `__` for internal use. The device types and instances defined in the file are as follows:
[Image: http://i.bosscdn.com/blog/15/32/33/42T-18.jpg]
When using PWM output to control the buzzer, information such as the PWM handle and channel number needs to be saved in the device. This leads to an updated device type definition.
[Image: http://i.bosscdn.com/blog/15/32/33/3636-19.jpg]
These members need to be initialized before use. The prototype for the initialization function is:
[Image: http://i.bosscdn.com/blog/15/32/33/5016-20.jpg]
Where `pwm_handle` is the standard PWM service handle, `chan` is the PWM channel number, and `duty_ns` and `period_ns` determine the loudness and frequency of the buzzer.
If SCT output is used, for example, with PIO0_24 corresponding to channel 1 of SCT, the initial call function is:
[Image: http://i.bosscdn.com/blog/15/32/33/D62-21.jpg]
The program uses `am_lpc82x_sct0_pwm_inst_init()` to get the PWM handle, sets the output PWM period to 400000ns (2.5KHz), and the pulse width is half the period, resulting in a 50% duty cycle.
An example of the initialization function is shown in Listing 8.29.
**Listing 8.29 Initialization Function Implementation Example**
[Image: http://i.bosscdn.com/blog/15/32/33/I38-22.jpg]
The program first validates the parameter, assigns the relevant members of the device instance, calls `am_buzzer_dev_register()` to add the device to the system, and finally configures the PWM output channel.
When adding a device, `p_funcs` is assigned to `&__g_buzzer_pwm_drv_funcs`, and `p_cookie` points to the device itself. The concrete implementation of the abstract method is contained in `__g_buzzer_pwm_drv_funcs`. See Listing 8.30 for a complete definition.
**Listing 8.30 Implementation of the Abstract Method**
[Image: http://i.bosscdn.com/blog/15/32/33/4344-23.jpg]
For ease of reference, the contents of the buzzer device interface file (`am_buzzer_pwm.h`) are shown in Listing 8.31.
**Listing 8.31 am_buzzer_pwm.h File Contents**
[Image: http://i.bosscdn.com/blog/15/32/33/3455-24.jpg]
Compared to other specific device interface files, this one does not contain the definition of the specific device type, nor is it a pointer to a specific device. This is because the buzzer is a single-instance device, and only one can be defined in the system. The device instance is defined directly in the implementation file, and the related types are not exposed to the user.
Similarly, since it is a single instance device, the initialization function must be a device instance defined inside the file, and there is no need to use a pointer to the device to specify the device to be initialized.
So far, the LED universal interface, HC595 interface, and buzzer interface have been described in detail, representing the typical three types of device interfaces in AMetal.
LED universal interface: Different devices are distinguished by unique IDs;
HC595 interface: Use handles to distinguish different devices, the handle is essentially a pointer to the device;
Buzzer interface: A single instance device that does not use any parameters to distinguish different devices.
**8.4 Temperature Acquisition Interface**
> > >
**8.4.1 Defining Interfaces**
**1. Interface Naming**
Since the object of operation is temperature, the interface name is prefixed with "am_temp_". The main operation is to read the current temperature. The definable interface name is:
- `Am_temp_read`
**2. Interface Parameters**
There may be multiple temperature sensors in a system, so a handle is used to distinguish them. The handle is defined as a pointer to the abstract temperature device. The type of the handle is defined as:
- `am_temp_handle_t`
The core function of the read temperature interface is to return the current temperature value. First, the type of the temperature value is defined, and then the return method is determined: return by return value or return by exit parameter.
Usually, a decimal value is used to represent the temperature, such as 37.5°C. However, due to the low-end hardware platforms, floating-point operations are inefficient. Therefore, the integer type is used to represent the temperature value after multiplying by 1000. For example, 37.5°C is represented as 37500. Using this method avoids the use of floating-point types and ensures precision.
The return value of the interface is defined as an error number of type `int`. Based on this, the prototype of the complete read temperature interface is:
[Image: http://i.bosscdn.com/blog/15/32/33/3123-26.jpg]
The corresponding class diagram is shown in Figure 8.11.
[Image: http://i.bosscdn.com/blog/15/32/33/NK-27.jpg]
**Figure 8.11 Temperature Acquisition Interface**
> > >
**8.4.2 Implementing the Interface**
**1. Abstract Temperature Acquisition Device Class**
According to the read temperature interface, the corresponding abstract method is defined and stored in a virtual function table:
[Image: http://i.bosscdn.com/blog/15/32/33/H07-28.jpg]
Similarly, the abstract method and `p_cookie` are defined together, forming an abstract temperature acquisition device:
[Image: http://i.bosscdn.com/blog/15/32/33/6141-29.jpg]
The specific temperature acquisition device is directly derived from the abstract device, and the abstract method of reading temperature is implemented according to the actual hardware.
In the read temperature interface, the handle is used as the first parameter, which is essentially a pointer to the device. The read temperature interface can directly call the abstract method implementation. See Listing 8.32 for details.
**Listing 8.32 Reading Temperature Interface Implementation**
[Image: http://i.bosscdn.com/blog/15/32/33/4263-30.jpg]
In the interface implementation, there is no hardware-related code, just a simple call to the abstract method. The abstract method needs to be implemented by a specific temperature acquisition device. Similarly, since the implementation of the read temperature interface is very simple, its implementation is often stored directly in the `.h` file as an inline function.
For ease of reference, the contents of the abstract temperature acquisition device interface file (`am_temp.h`) are shown in Listing 8.33, which contains the abstract method definitions, type definitions, and interface implementations associated with the abstract temperature acquisition device. See Figure 8.12.
[Image: http://i.bosscdn.com/blog/15/32/33/3D3-31.jpg]
**Figure 8.12 Abstract Temperature Collection Device Class**
**Listing 8.33 am_temp.h File Contents**
[Image: http://i.bosscdn.com/blog/15/32/33/21A-32.jpg]
**2. Specific Temperature Collection Equipment**
Taking the LM75B temperature sensor for temperature acquisition as an example, the implementation method of the specific temperature acquisition device is briefly described. First, a specific device class is derived based on the abstract device class. The class diagram is shown in Figure 8.13.
[Image: http://i.bosscdn.com/blog/15/32/33/20X-33.jpg]
[Image: http://i.bosscdn.com/blog/15/32/33/5363-34.jpg]
**Figure 8.13 Specific Temperature Collection Equipment Class**
`Am_temp_lm75_t` is a specific temperature collection device class. After this type, you can use this type to define a specific temperature acquisition device instance:
[Image: http://i.bosscdn.com/blog/15/32/33/41C-35.jpg]
The LM75B is a standard I2C slave device that requires the slave address of the LM75B to be used to read the temperature data. Since the slave address is related to the LM75 external pin level, the address information of the LM75 needs to be set by the user according to the actual hardware circuit.
Device-related information that needs to be provided by the user is stored in a new device information structure type:
[Image: http://i.bosscdn.com/blog/15/32/33/1361-36.jpg]
When using the LM75B onboard the AM824-Core, the 7-bit I2C slave address of the LM75B is 1001A2A1A0. Since A0, A1, and A2 are both tied low to ground, the 7-bit slave address of the onboard LM75B is available. It is 1001000, i.e., 0x48. Based on this, the device instance information corresponding to the onboard LM75B can be defined as follows:
[Image: http://i.bosscdn.com/blog/15/32/33/N43-37.jpg]
For the same reason, it is necessary to maintain a pointer to device information in the device class. In addition, since the temperature data is read from the LM75B using the I2C interface, the LM75B is equivalent to an I2C slave. To communicate with the I2C interface, two new members are added. The complete temperature acquisition device definition is:
[Image: http://i.bosscdn.com/blog/15/32/33/1341-38.jpg]
Before using the I2C interface to read the temperature from the LM75B, the assignment of each member of the device must be completed. This is usually done in the driver's initialization function. The prototype that defines the initialization function is:
[Image: http://i.bosscdn.com/blog/15/32/33/2403-39.jpg]
P_lm75 is a pointer to an instance of type `am_temp_lm75_t`;
P_devinfo is a pointer to the instance information of the `am_temp_lm75_info_t` type.
Handle is an I2C handle, which is convenient for reading temperature data using the I2C interface. The return value of the initialization function is the handle of the temperature acquisition device. The call form is as follows:
[Image: http://i.bosscdn.com/blog/15/32/33/5162-40.jpg]
The return value is the handle of the temperature acquisition device, which can be used as the actual parameter of the first parameter of the temperature acquisition interface. The implementation example of the initialization function is shown in Listing 8.34.
**Listing 8.34 Initialization Function Implementation Example**
[Image: http://i.bosscdn.com/blog/15/32/33/D48-41.jpg]
The program first establishes a standard I2C slave device, which facilitates subsequent reading of data using the I2C interface, then initializes the `p_info` member, completes the assignment of `p_funcs` and `p_cookie` in the abstract temperature acquisition device, and finally returns the device address as the user operating temperature acquisition device. Handle. Pfuncs is assigned the value of `&__g_temp_lm75_drv_funcs`, which contains a concrete implementation of the read temperature abstraction method. See Listing 8.35 for a complete definition.
**Listing 8.35 Implementation of the Abstract Method**
[Image: http://i.bosscdn.com/blog/15/32/33/5442-42.jpg]
In the read temperature implementation function `__temp_lm75_read()`, the current actual temperature value is first read from the LM75B using the I2C interface, as shown in Listing 8.35(6); then the data is simply processed, and the two-byte data is integrated. For a 16-bit signed temperature value `temp`, see Listing 8.35 (10 ~ 11); finally, after confirming that the `p_temp` pointer is valid, multiply `temp` by 125 and divide by 32, and the final result is used as the output temperature value.
Why multiply `temp` by 125 and then divide by 32? This is because the data directly read in the LM75B is 256 times the actual temperature value, i.e., actual temperature = `temp / 256`.
The temperature collection interface needs to return a temperature value that is 1000 times the actual temperature, namely:
`*p_temp = actual temperature * 1000 = temp / 256 * 1000 = temp * 1000 / 256`
Simplification is available:
[Image: http://i.bosscdn.com/blog/15/32/33/1335-43.jpg]
For ease of reference, the contents of the specific temperature acquisition device (LM75B) interface file (`am_temp_lm75.h`) are shown in Listing 8.36.
**Listing 8.36 am_temp_lm75.h File Contents**
[Image: http://i.bosscdn.com/blog/15/32/33/3F5-44.jpg]