【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A 6.定时器模拟PWM输出
[复制链接]
本帖最后由 乘简 于 2023-11-23 17:07 编辑
由于licheepi4a边上16个gpio中没有提供pwm引脚,所以只能用定时器来模拟,先来考虑一下可行性,拿一块24兆的51单片机来举例,因为24M单片机,每秒的时钟周期为24000000,pwm宽度为4096的话,那么其频率为24000000/4096=5859HZ,那么,想用定时器来模拟pwm的话,宽度与频率只能降低,那么频率应该只要在100hz左右就能满足需求,因为我们使用的交流电也才50hz,假如我使用1个1ms定时器,就是每秒执行1000次回调函数,即然要降低要求的话,肯定不能像单片机那样有4096的宽度下还能达到5859hz的频率,那么可以降低到10的话,正好可以调制出100hz的频率,如果用此pwm驱动电机转的话,有10种不同的速度可以选择,当然,我这里使用0.5ms的定时器,效果会更好,呵呵。。。
下面上驱动代码
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- #include <linux/uaccess.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/gpio.h>
- #include <linux/device.h>
- #include <linux/semaphore.h>
- #include <linux/irq.h>
-
-
-
- #define GPIO1_5 453
-
-
- #define GPIO_NAME1_5 "gpio1_5"
- #define GPIO_CNT (1)
-
-
- struct gpio_dev_t
- {
- dev_t devid;
- struct cdev cdev;
- struct class *class;
- struct device *device;
- struct device_node *nd;
- int irq_num;
- int gpio;
- };
- struct gpio_dev_t gpio_dev;
-
-
- static int gpio_init(void)
- {
- int res;
-
-
- gpio_dev.gpio = GPIO1_5;
- res = gpio_request(gpio_dev.gpio, GPIO_NAME1_5);
- if (res)
- {
- pr_err("key dev: Failed to request gpio\n");
- return res;
- }
-
-
- gpio_direction_output(gpio_dev.gpio, 1);
-
- return 0;
- }
-
-
- static int gpio_open(struct inode *inode, struct file *filp)
- {
-
- filp->private_data = &gpio_dev;
-
- printk("gpio_open\n");
- return 0;
- }
-
- static ssize_t gpio_write(struct file *filp, const char __user *buf, size_t count, loff_t *offt)
- {
- int ret = 0;
-
-
- char dat;
- ret = copy_from_user(&dat, buf, sizeof(dat));
- if(ret != 0) {
- return -1;
- }
-
-
- if(dat=='1'){
- gpio_set_value(gpio_dev.gpio, 1);
- }else{
- gpio_set_value(gpio_dev.gpio, 0);
- }
-
- return 0;
- }
-
-
- static int gpio_release(struct inode *inode, struct file *filp)
- {
- int res = 0;
- printk("gpio_release\n");
-
- return res;
- }
-
-
- static struct file_operations gpio_ops = {
- .owner = THIS_MODULE,
- .open = gpio_open,
- .write = gpio_write,
- .release = gpio_release,
- };
-
-
- static int gpio_register(void)
- {
- int ret = -1;
-
-
- ret = gpio_init();
-
-
-
-
-
- ret = alloc_chrdev_region(&gpio_dev.devid, 0, GPIO_CNT, GPIO_NAME1_5);
- if (ret < 0)
- {
- pr_err("%s Couldn't alloc_chrdev_region, ret = %d \r\n", GPIO_NAME1_5, ret);
- goto fail_region;
- }
-
-
-
- gpio_dev.cdev.owner = THIS_MODULE;
- cdev_init(&gpio_dev.cdev, &gpio_ops);
-
-
-
- ret = cdev_add(&gpio_dev.cdev, gpio_dev.devid, GPIO_CNT);
- if (ret < 0)
- {
- pr_err("fail to add cdev \r\n");
- goto del_unregister;
- }
-
-
- gpio_dev.class = class_create(THIS_MODULE, GPIO_NAME1_5);
- if (IS_ERR(gpio_dev.class))
- {
- pr_err("Failed to create device class \r\n");
- goto del_cdev;
- }
-
-
-
- gpio_dev.device = device_create(gpio_dev.class, NULL, gpio_dev.devid, NULL, GPIO_NAME1_5);
- if (IS_ERR(gpio_dev.device))
- {
- goto destroy_class;
- }
-
- return 0;
-
- destroy_class:
- device_destroy(gpio_dev.class, gpio_dev.devid);
- del_cdev:
- cdev_del(&gpio_dev.cdev);
- del_unregister:
- unregister_chrdev_region(gpio_dev.devid, GPIO_CNT);
- fail_region:
- gpio_free(gpio_dev.gpio);
- return -EIO;
- }
-
-
- static void gpio_unregister(void)
- {
-
- cdev_del(&gpio_dev.cdev);
-
- unregister_chrdev_region(gpio_dev.devid, GPIO_CNT);
-
- device_destroy(gpio_dev.class, gpio_dev.devid);
-
- class_destroy(gpio_dev.class);
-
-
- gpio_free(gpio_dev.gpio);
- }
-
-
- static int __init gpio_driver_init(void)
- {
- pr_info("gpio_driver_init\n");
- return gpio_register();
- }
-
-
- static void __exit gpio_driver_exit(void)
- {
- pr_info("gpio_driver_exit\n");
- gpio_unregister();
- }
-
-
- module_init(gpio_driver_init);
- module_exit(gpio_driver_exit);
-
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("乘简");
-
应用代码pwm.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <signal.h>
- #include <time.h>
- #include <sys/time.h>
-
- timer_t timerid;
- int fd;
- int pwm_width=0;
- int pwm_low=0;
- int pwm_count=0;
- int pwm_start=0;
- char pwm_value=0;
-
- long get_system_time_microsecond()
- {
- struct timeval timestamp = {};
- if (0 == gettimeofday(×tamp, NULL))
- return timestamp.tv_sec * 1000000 + timestamp.tv_usec;
- else
- return 0;
- }
-
-
- void setLow(){
- if(pwm_value != '0'){
- pwm_value = '0';
- write(fd, &pwm_value, 1);
- }
- }
-
-
- void setHigh(){
- if(pwm_value != '1'){
- pwm_value = '1';
- write(fd, &pwm_value, 1);
- }
- }
-
-
- void setStart(){
- setHigh();
- pwm_start = 1;
- }
-
-
- void setClose(){
- pwm_start = 0;
- }
-
- void timer_handler(int signo, siginfo_t *info, void *v)
- {
- if(pwm_start){
- if(pwm_count < pwm_low){
- setLow();
- }else{
- setHigh();
- }
- pwm_count = ++pwm_count % pwm_width;
- }else{
- if(pwm_value != 0){
- pwm_count=0;
- setHigh();
- pwm_value=0;
- }
- }
- }
-
- int main(int argc, char *argv[])
- {
- struct sigevent sev;
- struct itimerspec its;
- struct sigaction sa;
-
- if(argc!=3){
- printf("./pwm 5 3\n");
- return -1;
- }
-
- pwm_width = atoi(argv[1]);
- pwm_low = atoi(argv[2]);
- if(pwm_low > pwm_width)pwm_low = pwm_width;
-
- fd=open("/dev/gpio1_5", O_RDWR);
- if(fd<0){
- printf("can't open file %s",argv[1]);
- return -1;
- }
-
-
- sa.sa_flags = SA_SIGINFO;
- sa.sa_sigaction = timer_handler;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
- printf("sigaction() failed\n");
- return 1;
- }
-
-
- sev.sigev_notify = SIGEV_SIGNAL;
- sev.sigev_signo = SIGRTMIN;
- sev.sigev_value.sival_ptr = &timerid;
- if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
- printf("timer_create() failed\n");
- return 1;
- }
-
-
- its.it_value.tv_sec = 0;
- its.it_value.tv_nsec = 500000;
- its.it_interval.tv_sec = 0;
- its.it_interval.tv_nsec = 500000;
- if (timer_settime(timerid, 0, &its, NULL) == -1) {
- printf("timer_settime() failed\n");
- return 1;
- }
-
- setStart();
-
-
- while (1) {
- sleep(1);
- }
-
- close(fd);
- return 0;
- }
-
执行效果测试,输入
sudo ./app 10 0
此时量GPIO1_5的电压为1.8V
sudo ./app 10 2
此时量电压为1.44V
sudo ./app 10 5
电压为0.9V
sudo ./app 10 9
电压为0.17V
sudo ./app 10 10
此时为0V
但这种办法,会占用18%左右的CPU,不知道有没有更好的办法实现
|