2021-05-30


前言

此篇为STM32F407 DMA的学习。


一、pandas是什么?

DMA:叫做直接存储器访问,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传输数据的通道,从而大大提高CPU工作效率。
在这里插入图片描述

在这里插入图片描述

二、分布介绍

1,外设通道
STM32F407系列志愿丰富,具有两个DMA控制器,同时外设繁多,为实现正常传输,DMA需要通道选择控制。每个DMA控制器具有8个数据流,每个数据流对应8个外设请求。
外设通道选择要解决的主要问题是决定哪一个外设作为该数据流的源地址或者目标地址。
注:DMA控制器会通过DMA数据流X配置寄存器DMA_SxCR的CHSEL[2:0]位选择对应的通道作为该数据流的目标外设。
在这里插入图片描述
2.数据流仲裁
DMA外设通道
一个DMA控制器对应8个数据流,数据流包含要传输数据的源地址,目标地址,数据长度等待信息,如果我们需要同时使用同一个DMA控制多个外设请求时,那必然需要同时使用多个数据流,那究竟哪一个数据流具有优先传输的权利呢?这就需要仲裁器来管理判断了。

数据流传输优先级配置
1,配置DMA_SxCR寄存器PL[1:0]位,可以设置位非常高,高,中,低四个等级。
2,如果两个或者以上数据流软件设置优先级一样,则他们优先级取决于数据流编号,编号越低越具有优先权。

3,数据FIFO
每一个数据流都有一个独立的4字节FIFO。DMA传输具有FIFO模式和直接模式。
1,直接模式:
每个DMA请求会立即启动对存储器的传输。当在直接模式(禁止FIFO)下,将DMA请求配置为存储器达到外设模式传输数据时,DMA仅会将一个数据从存储器预加载到内部FIFO,从而确保一旦外设触发DMA请求时则立即传输。
2,FIFO模式:
可通过控制寄存器DMA_SxFCR的FTH[1:0]位来设置FIFO阈值级别为FIFO大小的1/4,1/2,3/4.如果数据存储量达到阈值级别时,FIFO内容将传输到目标中。

4、5存储器端口和外设端口
在这里插入图片描述
DMA传输模式:
DMA1只是外设到存储器和存储器到外设两种模式,DMA2除前面两种外还支持存储器到存储器的传输模式。模式选择可以通过DMA_SxCR寄存器的DIR[1:0]位控制。

DMA传输的源,目的,长度
1,DMA_SxPAR寄存器:设置外设寄存器地址
2,DMA_SxM0AR寄存器:设置存储器地址
3,DMA_SxCR寄存器:DIR[1:0]位配置数据的传输方向
4,DMA_CNDTRx寄存器:写入需要传输的数据量,(0-65535)
5,DMA_SxCR寄存器中的PSIZE和MSIZE位:设置源和目的的数据宽度,两边的位宽尽量保持一致。

DMA增量设置:
根据设置DMA_SxCR寄存器中的PINC和MINC位的状态,外设和存储器指针在每次传输后递增或保持常量。
当设置位增量模式时,下一个传输的地址将是前一个地址的增量值,增量值取决于所选的数据宽度1、2、4。

DMA循环模式:
循环模式用于处理循环缓冲区和连续的数据传输 ( 如 ADC 的扫描模式 ) 。可以使用 DMA_SxCR 寄存器中的 CIRC 位使能此特性。
当启动了循环模式,一组的数据传输完成时,计数寄存器将会自动地被恢复成配置该通道时设置的初值,DMA操作将会继续进行。

DMA单次传输和突发传输
1,DMA传输类型有单次(Single)传输和突发(Burst)传输。DMA 控制器可以产生单次传输或 4 个、8 个和 16个节拍的增量突发传输。
2,突发大小通过软件针对两个 AHB端口独立配置,配置时使用DMA_SxCR 寄存器中的MBURST[1:0] PB
URST[1:0] 位。
3,为确保数据一致性,形成突发的每一组传输都不可分割:在突发传输序列期间,AHB传输会锁定,并且AHB总线矩阵的仲裁器不解除对 DMA 主总线的授权。

在这里插入图片描述

以下是一个可能的Java实现: ```java import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; public class RentPlanGenerator { private static final double RENT_INCREASE_RATE = 0.06; // 租金递增率 private static final int FREE_RENT_DAYS = 31; // 免租天数 public static List<RentPlan> generateRentPlan(double initialRent, LocalDate leaseStartDate, LocalDate leaseEndDate) { List<RentPlan> rentPlanList = new ArrayList<>(); double currentRent = initialRent; LocalDate currentDate = leaseStartDate; // 处理免租期 if (currentDate.isBefore(leaseStartDate.plusDays(FREE_RENT_DAYS))) { currentDate = leaseStartDate.plusDays(FREE_RENT_DAYS); } while (currentDate.isBefore(leaseEndDate)) { LocalDate nextIncreaseDate = currentDate.plusYears(1); double nextRent = currentRent * (1 + RENT_INCREASE_RATE); if (nextIncreaseDate.isBefore(leaseStartDate.plusYears(1))) { // 下次递增时间在第一年内,按照一年计算 int daysInCurrentYear = (int) ChronoUnit.DAYS.between(currentDate, nextIncreaseDate); rentPlanList.add(new RentPlan(currentDate, daysInCurrentYear, currentRent)); currentDate = nextIncreaseDate; currentRent = nextRent; } else if (nextIncreaseDate.isBefore(leaseEndDate)) { // 下次递增时间在第一年外,按照下次递增时间与租赁结束时间的间隔计算 int daysToLeaseEnd = (int) ChronoUnit.DAYS.between(currentDate, leaseEndDate); rentPlanList.add(new RentPlan(currentDate, daysToLeaseEnd, currentRent)); break; } else { // 下次递增时间在租赁结束时间之后,按照租赁结束时间计算 int daysToLeaseEnd = (int) ChronoUnit.DAYS.between(currentDate, leaseEndDate); rentPlanList.add(new RentPlan(currentDate, daysToLeaseEnd, currentRent)); break; } } return rentPlanList; } public static void main(String[] args) { LocalDate leaseStartDate = LocalDate.of(2021, 3, 1); LocalDate leaseEndDate = LocalDate.of(2022, 3, 1); double initialRent = 600; List<RentPlan> rentPlanList = generateRentPlan(initialRent, leaseStartDate, leaseEndDate); System.out.printf("%-12s%-12s%-12s%n", "时间", "天数", "租金"); for (RentPlan rentPlan : rentPlanList) { System.out.printf("%-12s%-12d%-12.2f%n", rentPlan.getStartDate(), rentPlan.getDays(), rentPlan.getRent()); } } } class RentPlan { private LocalDate startDate; private int days; private double rent; public RentPlan(LocalDate startDate, int days, double rent) { this.startDate = startDate; this.days = days; this.rent = rent; } public LocalDate getStartDate() { return startDate; } public int getDays() { return days; } public double getRent() { return rent; } } ``` 这个程序首先定义了租金递增率免租天数的常量,然后提供了一个静态方法 `generateRentPlan` 来生成租金计划列表。该方法接受三个参数:初始月租金、租赁开始时间租赁结束时间。 具体实现时,我们使用循环来逐月生成租金计划。在每次循环中,我们首先计算下次递增租金的时间金额。然后根据下次递增时间与租赁开始时间的间隔,决定本次循环处理的天数租金金额。最后将这些信息保存到一个 `RentPlan` 对象中,并添加到租金计划列表中。 在主函数中,我们使用 `generateRentPlan` 方法生成租金计划列表,并以表格形式输出。输出结果如下: ``` 时间 天数 租金 2021-04-01 30 600.00 2021-05-01 31 636.00 2021-06-01 30 674.16 2021-07-01 31 713.57 2021-08-01 31 754.29 2021-09-01 30 796.39 2021-10-01 31 840.94 2021-11-01 30 887.02 2021-12-01 31 934.72 2022-01-01 31 984.12 2022-02-01 28 1035.30 ``` 可以看到,程序正确地根据递增周期递增率生成了每个月的租金计划,并且考虑了免租期的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值