|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
linux开发板驱动使用timer输出800khz,周期1.25us,占空比66%的方波。失败,用示波器测量的结果是周期为125us,占空比为50%。不论怎么改变high_time的值,占空比一直是50%不变,不知道是那有问题,还请小伙伴们指点,谢谢!
main.cpp:
#include "gpio.h"
#include <iostream>
#include <unistd.h>
void generate_pwm(GPIO &gpio, Timer &timer); // 声明 generate_pwm 函数
int main() {
GPIO gpio;
gpio.Init();
Timer timer;
timer.Init();
gpio.ConfigPin(PORT::PE, 22, PIN_MODE::OUT);
gpio.ConfigPin(PORT::PE, 21, PIN_MODE::OUT);
int a = 0, b = -1;
for (int i = 0; i < 2; i++) {
generate_pwm(gpio, timer); // 生成PWM信号
sleep(1);
}
gpio.Free();
return 0;
}
gpio.cpp:
#include "gpio.h"
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <thread>
#include <chrono>
#include <time.h> // 添加这个头文件来使用 clock_nanosleep
#define TIMER_BASE 0x01C20C00 // 替换为你的定时器基地址
#define TIMER_CTRL_OFFSET 0x00
#define TIMER_INTV_VALUE_OFFSET 0x04
#define TIMER_CUR_VALUE_OFFSET 0x08
#define GPIO_BASE 0x01C20800 // 替换为你的GPIO基地址
#define GPIO_SET_OFFSET 0x1C
#define GPIO_CLR_OFFSET 0x28
#define PE22 (1 << 22) // PE22引脚
// GPIO 类的构造函数和析构函数
GPIO::GPIO() : fd(-1), gpio_map(nullptr), PIO(nullptr) {}
// GPIO 类的析构函数
GPIO::~GPIO() {
Free();// 调用 Free 方法释放资源
}
// 初始化 GPIO
void GPIO::Init() {
// 打开 /dev/mem 设备文件,以读写方式打开
if ((fd = open("/dev/mem", O_RDWR)) == -1) {
std::cerr << "open error /dev/mem" << std::endl;
return;
}
PageSize = sysconf(_SC_PAGESIZE);// 获取系统页面大小
PageMask = (~(PageSize - 1));// 计算页掩码
addr_start = PIO_BASE_ADDRESS & PageMask;// 计算映射起始地址
addr_offset = PIO_BASE_ADDRESS & ~PageMask;// 计算地址偏移量
// 使用 mmap 将设备内存映射到用户空间
gpio_map = (unsigned int *)mmap(NULL, PageSize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr_start);
if (gpio_map == MAP_FAILED) {
std::cerr << "mmap error" << std::endl;
close(fd);// 映射失败,关闭文件描述符
return;
}
//计算GPIO寄存器地址..
PIO = (PIO_Map *)((unsigned int)gpio_map + addr_offset);
close(fd);
}
// 配置指定引脚的模式
void GPIO::ConfigPin(PORT port, unsigned int pin, PIN_MODE mode) {
if (gpio_map == nullptr) return; // 若 gpio_map 为 nullptr,直接返回
PIO->Pn[port].CFG[pin / 8] &= ~((unsigned int)0x07 << (pin % 8) * 4);
PIO->Pn[port].CFG[pin / 8] |= ((unsigned int)mode << (pin % 8) * 4);
}
// 设置指定引脚的电平
void GPIO::SetPin(PORT port, unsigned int pin, unsigned int level) {
if (gpio_map == nullptr) return;
if (level)
PIO->Pn[port].DAT |= (1 << pin);// 设置引脚输出高电平
else
PIO->Pn[port].DAT &= ~(1 << pin);// 设置引脚输出低电平
}
// 释放 GPIO 资源
int GPIO::Free() {
if (munmap(gpio_map, PageSize * 2) == 0) {
std::cout << "unmap success!" << std::endl;
} else {
std::cerr << "unmap failed!" << std::endl;
}
return 0;
}
// 设置定时器
// Timer 类的构造函数和析构函数
Timer::Timer() : fd(-1), timer_map(nullptr), timer(nullptr) {}
Timer::~Timer() {
Free(); // 调用 Free 方法释放资源
}
// 初始化定时器
void Timer::Init() {
// 打开 /dev/mem 设备文件,以读写方式打开
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
std::cerr << "open error /dev/mem" << std::endl;
return;
}
PageSize = sysconf(_SC_PAGESIZE); // 获取系统页面大小
PageMask = (~(PageSize - 1)); // 计算页掩码
addr_start = TIMER_BASE & PageMask; // 计算映射起始地址
addr_offset = TIMER_BASE & ~PageMask; // 计算地址偏移量
// 使用 mmap 将设备内存映射到用户空间
timer_map = (unsigned int *)mmap(NULL, PageSize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr_start);
if (timer_map == MAP_FAILED) {
std::cerr << "mmap error" << std::endl;
close(fd); // 映射失败,关闭文件描述符
return;
}
// 计算定时器寄存器地址
timer = (volatile unsigned int *)((unsigned int)timer_map + addr_offset);
close(fd);
}
// 设置时钟源为OSC24M
void Timer::SetClockSource() {
if (timer) {
timer[TIMER_CTRL_OFFSET / 4] &= ~(0x3 << 2); // 清除时钟源位
timer[TIMER_CTRL_OFFSET / 4] |= (0x1 << 2); // 设置时钟源为OSC24M
}
}
void Timer::SetPeriod(unsigned int period_ns) {
if (timer) {
// 计算计数值,每个计数单位大约为41.67纳秒
unsigned int timer_counts = static_cast<unsigned int>(period_ns / 41.67/100);
// 设置定时器的间隔值寄存器和当前值寄存器
timer[TIMER_INTV_VALUE_OFFSET / 4] = timer_counts;
timer[TIMER_CUR_VALUE_OFFSET / 4] = timer_counts;
}
}
// 启动定时器
void Timer::Start() {
if (timer) {
timer[TIMER_CTRL_OFFSET / 4] = 0x3; // 启用定时器,自动重载模式
}
}
// 停止定时器
void Timer::Stop() {
if (timer) {
timer[TIMER_CTRL_OFFSET / 4] = 0x0; // 停止定时器
}
}
// 释放 Timer 资源
int Timer::Free() {
if (timer_map && munmap((void *)timer_map, PageSize * 2) == 0) { // 确保 timer_map 有效
std::cout << "unmap success!" << std::endl;
} else {
std::cerr << "unmap failed!" << std::endl;
}
return 0;
}
void generate_pwm(GPIO &gpio, Timer &timer) {
const int period_ns = 1250; // 设置周期为1.25µs
const int high_time = 825; // 66% of 1250ns => 825ns
const int low_time = period_ns - high_time; // 余下的时间为低电平
gpio.ConfigPin(PORT::PE, 22, PIN_MODE::OUT);
gpio.ConfigPin(PORT::PE, 21, PIN_MODE::OUT);
while (true) {
gpio.SetPin(PORT::PE, 21, 1);
timer.SetPeriod(82); // 设置高电平时间
timer.Start();
std::this_thread::sleep_for(std::chrono::nanoseconds(high_time))
timer.Stop();
gpio.SetPin(PORT::PE, 21, 0);
timer.SetPeriod(43); // 设置低电平时间
timer.Start();
std::this_thread::sleep_for(std::chrono::nanoseconds(low_time))
timer.Stop();
}
}
gpio.h:
#ifndef GPIO_H
#define GPIO_H
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cstdint> // 添加这个头文件来定义 uint32_t
#include <fcntl.h>
// 定义 PIO_BASE_ADDRESS 和页面大小
#define PIO_BASE_ADDRESS 0x01C20800
// 定义 PIO_Struct 结构体,描述每个 PIO 控制器的寄存器布局
typedef struct {
unsigned int CFG[4]; // 配置寄存器数组
unsigned int DAT; // 数据寄存器
unsigned int DRV0; // 驱动能力寄存器0
unsigned int DRV1; // 驱动能力寄存器1
unsigned int PUL0; // 上拉寄存器0
unsigned int PUL1; // 上拉寄存器1
} PIO_Struct;
// 定义 PIO_Map 结构体,描述所有 PIO 控制器的映射
typedef struct {
PIO_Struct Pn[7]; // PIO_Struct 数组,对应7个 PIO 控制器
} PIO_Map;
typedef enum {
PA = 0,
PB = 1,
PC = 2,
PD = 3,
PE = 4,
PF = 5,
PG = 6,
} PORT;
typedef enum {
IN = 0x00,
OUT = 0x01,
AUX = 0x02,
INT = 0x06,
DISABLE = 0x07,
} PIN_MODE;
// GPIO 类定义
class GPIO {
public:
GPIO(); // 构造函数
~GPIO(); // 析构函数
void Init(); // 初始化 GPIO
void ConfigPin(PORT port, unsigned int pin, PIN_MODE mode); // 配置指定引脚的模式
void SetPin(PORT port, unsigned int pin, unsigned int level); // 设置指定引脚的电平
int Free(); // 释放 GPIO 资源
private:
int fd; // 文件描述符
unsigned int *gpio_map; // 指向内存映射的 GPIO 控制器寄存器
PIO_Map *PIO; // 指向 PIO_Map 的指针,用于访问 PIO 控制器的映射
unsigned int addr_start; // 映射起始地址
unsigned int addr_offset; // 地址偏移量
unsigned int PageSize; // 页面大小
unsigned int PageMask; // 页掩码
};
class Timer {
public:
Timer();
~Timer();
void Init();
void SetPeriod(unsigned int period_ns);
void Start();
void Stop();
void SetClockSource();
bool CheckInterrupt();
private:
int fd;
unsigned int PageSize;
unsigned int PageMask;
unsigned int addr_start;
unsigned int addr_offset;
volatile unsigned int *timer_map;
volatile unsigned int *timer;
int Free();
};
void delay_ns(uint32_t ns);
void setup_timer();
void init_timer();
//void generate_pwm(gpio, timer);
void generate_pwm(GPIO &gpio, Timer &timer);
void delay2_ns(uint32_t ns); // 声明纳秒级延时函数
void delay3_ns(long nanoseconds); // 声明纳秒级延时函数
#endif // GPIO_H
|
|