1.1 友善之臂2440的代码翻译,加了备注和没用的解释。

(友善mini2440的最简单的代码加注释。)

1:系统编程概述

linux操作系统为我们提供了一套完整的“资源管理机制”和“任务的调度机制”。我们通过使用这些“机制”可以轻易的在一台linux主机上运行多个任务,从而提高多个任务的运行效率。

2:led、按键、蜂鸣器代码详解

开发板说明书为我们提供了一些简单的列程来让我们了解开发板如何使用。如led的列程就可以认为是I/O口的输出列程、按键就是I/O的输入与外部中断列程。由于linux系统中,应用软件与驱动程序有着严格的区分,所以我们本章先以几个简单的程序的应用为列,浅浅的对linux操作系统的系统编程做一个了解。

 

一:led控制程序。

就像在我们刚开始学习51单片机的时候一样,流水灯程序永远是最经典的,也永远是最早接触的。它就像我们学习编程语言中的“hello word”一般,叫你清楚地认识到你又要学习一款新的单片机了。

由于在linux系统中所有的硬件都被虚拟成一个文件,所以我们今天使用的led也不列外。从设备种类上看,led设备属于“字符型设备”。简单地说,就是一种以字符为单位,可读,可写的设备。就好比一个“字符串”、一个“串口”、一个“键盘”等。

字符型设备是linux中比较简单而常用的设备(可读可写的设备)。本程序实现了一个在应用程序(lcds)中调用linux字符驱动("/dev/leds0")的列子。

在学习前我们需要先对本程序中使用的“系统函数”进行一些了解。

main() 任务主函数

sscanf() 字符串输入

open() 打开某文件\设备

ioctl() I/O控制函数

函数用法见 百度百科 或 Linux-C-CHM”

由于有些人是初次接触linux,对它的函数以及调用的规律的了解基本为零,所以对于这套程序主要练习的是怎么把程序从交叉编译环境中移动到开发板,并运行起来,至于代码的理解长度暂时只要知道函数的功能就可以了,不要太纠结于函数怎么实现的。(驱动开发板已内置)

本程序通过main函数所传回的两个参数,通过第一条if语句中所包含的函数进行处理,找出需要亮、灭的小灯。最后打开设备文件"/dev/leds0",通过ioctl()控制亮灭。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
 
int main(int argc, char **argv)      //main函数传参,char **argv为定义了指针的指针,类似	 //于char *argv[](数组/地址的指针),在这里可以互用。 
{
<span style="white-space:pre">	</span>int on;	 //亮灭标志
<span style="white-space:pre">	</span>int led_no;	 //led序号
<span style="white-space:pre">	</span>int fd;	 //文件描述符
<span style="white-space:pre">	</span>//判断main()传参的正确性,不正确调用系统输出函数“fprent()”输出错误提示并结束//程序
<span style="white-space:pre">	</span>if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
    <span style="white-space:pre">		</span>on < 0 || on > 1 || led_no < 0 || led_no > 3) {
<span style="white-space:pre">	</span>fprintf(stderr, "Usage: leds led_no 0|1\n");
<span style="white-space:pre">	</span>exit(1);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>fd = open("/dev/leds", 0);	 //开启文件
<span style="white-space:pre">	</span>if (fd < 0) {	 //判断是否开启成功,不成功在开启一次
<span style="white-space:pre">	</span>fd = open("/dev/leds", 0);
}
if (fd < 0) {	 //两次不成功输出错误并结束程序
perror("open device leds");
exit(1);
}
ioctl(fd, on, led_no);	 //为驱动程序传参
close(fd);	 //关闭文件描述
return 0;	 //返回人物完成标志
}
附:流水灯程序(自写)、、程序没有退出程序。
#include<stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
//函数声明
void open_led(int on,int led_on);
int led_ons(int leds,char i);
void delay(int times);
//主函数
int main(void)
{
int last;	 //现在要关闭的led的编号
int off;	 //要关闭的led距离点亮的led的位置
int led_on=-1;	//现在需要点亮的led的编号
int f_led;	 //循环熄灭标志
while(1)
 {
    off=1;	 //位置间隔复位
    led_on++;	 //点亮序列号增加
    if(led_on==4)
    {
        led_on=0;
    }
    open_led(1,led_on);	//开启点亮小灯
    for(f_led=3;f_led>0;f_led--) //关闭其余三个小灯
    {
    last=led_ons(led_on,off);
    open_led(0,last);
    off++;
    }
    delay(5000);	 //延时函数
 }
}
void open_led(int on,int led_on)	//开启关闭led程序
{
int fd;
fd = open("/dev/leds0", 0);
if (fd < 0)
{
    fd = open("/dev/leds", 0);
}
if (fd < 0)
{
    perror("open device leds");
    exit(1);
}
/*通过系统调用 ioctl 和输入的参数控制 led*/
ioctl(fd, on, led_on);
/*关闭设备句柄*/
close(fd);                          //delete????????
}
int led_ons(int leds,char i)	 //关闭编号选择函数
{
    int a;
    a=leds;
    for(i;i>0;i--)
    {
        a++;
        if(a==4)
         {a=0;}
    }
    return a;
}
void delay(int times)	 //延时函数
{
    int i;
    for(;times>0;times--)
      for(i=0;i<400;i++);
}


二:按键程序。

作为接触的第二个程序,按键测试大的应用程序对驱动的调用也比较简单。本程序实现了一个在应用程序(buttons)中调用linux驱动("/dev/buttons")的列子。和led程序相比,本程序并没有困难多少,但相对与本程序的驱动(调用中断的驱动程序)相对复杂,如果拿此程序作为入门建议暂时不要细读他的驱动。

重点掌握函数:

read();

函数用法见 百度百科 或 Linux-C-CHM ”

此程序和LED程序类似,对程序驱动打开后不停的进行读(read();)操作,主要的目的还是为了适应环境与开发过程,。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
int main(void)
{
int buttons_fd;
char buttons[6] = {'0', '0', '0', '0', '0', '0'};
buttons_fd = open("/dev/buttons", 0);//打开驱动文件
if (buttons_fd < 0) {
perror("open device buttons");
exit(1);
}
for (;;) {
char current_buttons[6];
int count_of_changed_key;
int i;
//从驱动文件中读取六个字符,返回长度六。如果返回值不是六则输//出错误
if (read
(buttons_fd, current_buttons, sizeof current_buttons) 
!= sizeof current_buttons) 
{  	 perror("read buttons:");
exit(1);}
//将读取参数循环送入缓存,并输出
for (i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++) {
if (buttons[i] != current_buttons[i]) {
buttons[i] = current_buttons[i];
printf("%skey %d is %s", count_of_changed_key? ", ": "", i+1, buttons[i] == '0' ? "up" : "down");
count_of_changed_key++;
}
}
if (count_of_changed_key) {//输出换行标志
printf("\n");
}
}
close(buttons_fd);	//关闭驱动
return 0;	 //退出程序
}


3:蜂鸣器pwm

蜂鸣器测试程序与LED一样,依然是一个调用字符型设备的应用程序。本程序实现了一个在应用程序(pwm_test)中调用linux驱动("/dev/pwm")的列子。

库函数的调用

isatty();

tcgetattr();

tcsetattr();

getchar();

任务启动后会改变终端模式。进入软件后会取消使其更像一个任务的调试窗口,并且输出相应的提示。最后通过输入“+”“-”的次数修改频率参数,在通过ioctl函数传参给驱动程序。

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
 
#define PWM_IOCTL_SET_FREQ	 1
#define PWM_IOCTL_STOP	 0//蜂鸣器停向参数
 
#define	ESC_KEY	 0x1b
 
static int getch(void)	 //键盘输入函数,主要调用getchar。
{
struct termios oldt,newt;	//设置两个关于串口设置的结构体。
int ch;	 //getchar数据存放位
 
if (!isatty(STDIN_FILENO)) {//如果参数desc所代表的文件描述词为一终端机则返回1,
//否则返回0。STDIN_FILENO 是 1,一个文件描述符,代表标准输入
fprintf(stderr, "this problem should be run at a terminal\n");
exit(1);  //跳出程序(注意)
}
// save terminal setting
if(tcgetattr(STDIN_FILENO, &oldt) < 0) {//tcgetattr函数用于获取与终端相关的参数,放如oldt
perror("save the terminal setting");
exit(1);
}
//记录旧的终端输入设置
 
// set terminal as need
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );	// 设置新的(终端不显示输入符号)
if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) {
perror("set terminal");
exit(1);
}
 
ch = getchar();	 //输入(+或—)~~
 
// restore termial setting
if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) {//恢复终端设置。
perror("restore the termial setting");
exit(1);
}
return ch;	 //返回输入结果
}
 
static int fd = -1;	 //文件描述符,为调用驱动准备
static void close_buzzer(void);	 //关闭驱动文件的声明
static void open_buzzer(void)	 //打开驱动文件
{
fd = open("/dev/pwm", 0);	 //open的第一个参数是驱动名称,第二个是设置w、r、x
if (fd < 0) {
perror("open pwm_buzzer device");
exit(1);
}
 
// any function exit call will stop the buzzer
atexit(close_buzzer);	 //注册终止,在main结束后终止所有注册了的函数。结束	 //时与登记时候的顺序相反
}
 
static void close_buzzer(void)	 //关闭驱动
{
if (fd >= 0) {
ioctl(fd, PWM_IOCTL_STOP);//送入结束指令。
close(fd);	     //释放驱动(不释放其他程序没法用)
fd = -1;	     //复位fd
}
}
 
static void set_buzzer_freq(int freq)
{
// this IOCTL command is the key to set frequency
int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, freq);
//像驱动输入所要使用的频率(蜂鸣)
if(ret < 0) {
perror("set the frequency of the buzzer");
exit(1);
}
}
static void stop_buzzer(void)
{
int ret = ioctl(fd, PWM_IOCTL_STOP);	 //蜂鸣器停响
if(ret < 0) {
perror("stop the buzzer");
exit(1);
}
}
 
int main(int argc, char **argv)	 //main参数其实没用(程序未用)
{
int freq = 1000 ;	 //输入频率,单位时间内的占空比
//初值1000
open_buzzer();	 //打开驱动,前面有定义
 
printf( "\nBUZZER TEST ( PWM Control )\n" );
printf( "Press +/- to increase/reduce the frequency of the BUZZER\n" ) ;
printf( "Press 'ESC' key to Exit this program\n\n" );
while( 1 )	 //死循环,重复等待输入参数
{
int key;	 //输入的+或-号的寄存
 
set_buzzer_freq(freq);	 //输入频率值
printf( "\tFreq = %d\n", freq );
 
key = getch();	 //调用输入函数输入数值
 
switch(key) {	 //判断输入的数值以及对其的处理
case '+':
if( freq < 20000 )	 //增加freq的大小
freq += 10;
break;
 
case '-':
if( freq > 11 )	 //减少freq的大小
freq -= 10 ;
break;
 
case ESC_KEY:	 //ESC退出
case EOF:
stop_buzzer();
exit(0);
 
default:	 //输入其他参数则什么也不做
break;
}
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值