ARM裸板开发:07_IIC 通过IIC总线接口读写时钟芯片时间参数实现的总结_weixin_34024034的博客-程序员宅基地

技术标签: shell  嵌入式  

问题一:程序直接在iRAM内部可正常执行,而程序搬移(Nand ->SDRAM)之后,就不能正常运行了
#define NAND_SECTOR_SIZE    2048
 
/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
 
//if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
 
    if (start_addr & NAND_BLOCK_MASK)
        return;    /* 地址不对齐则退出 */
 
    /* 选中芯片 */
    nand_select_chip();
 
    for(i=start_addr; i < (start_addr + size);)
    {
      /* 发出READ0命令 */
      write_cmd(0);
      /* Write Address */
      write_addr(i);      
      write_cmd(0x30);
 
      /* 等待数据就绪 */
      wait_idle();
 
      for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
      {
          *buf = read_data();
          buf++;
      }
    }
 
    /* 取消片选信号 */
    nand_disselect_chip();
    
    return;
}
查看韦东山nand_read代码,发现有这样一条语句:
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
        return;    /* 地址或大小不对齐则退出 */
而在start.S中,size = __bss_start - 0x30000000,这个大小显然不能保证是2048的倍数(事实确也如此,并不是2048的倍数,也就导致了nand_read函数并未正常执行)
地址或大小不对齐则退出,这种方式有问题,大小确实也没必要对齐。若大小刚好超出一个块内存,就将这个块内存完整copy即可。
 
问题二:ARM9裸板开发过程,硬件并不不支持除法运算,所以除法以及取余操作如何实现?
/*
* val    : 需要转换的整形值
* bit    : 该整形值的位数
* pdst    : 转换字符串输出
*/
void int_to_str(int val, unsigned char bit, char *pdst)
{
    //根据val位数确定mult. E.G. val-1位 -> mult=1
    int mult;
    for (mult = 1; --bit != 0; mult *= 10);
 
    for ( ; mult != 0; mult /= 10)
    {
        *pdst++ = (char)(val/mult + '0');
        val %= mult;
    }
}
1、网上搜了一些方法,基本思想是运用移位运算,比较,以及乘法操作等实现。
比如:sum / 6    可转换为    sum * (1 / 6)    (1 / 6) -> (5461 / 32768),而 1/32768 即为(1 >> 15)。这种方法主要是通过将分数转换为被除数是2的次幂的方式实现的,有误差。
2、使用库函数。参考韦东山的方式,在07_IIC工程中添加 includelib两个依赖库。同时修改对应地Makefile文件,可以正常编译通过。
#Time: 2018-4-19 11:56:52
#Proj: General Makefile
#Designed by DZH for JZ2440
 
#Define vars
TARGET_NAME    := iic
#final target
TARGET    := $(TARGET_NAME).bin
#temp target
BUILD    := $(TARGET_NAME).elf
#disa target
DISA    := $(TARGET_NAME).dis
 
#default boot from NAND Flash
ENV        ?= NAND
 
OBJS    += start.o
OBJS    += init.o
OBJS    += main.o
OBJS    += iic.o
OBJS    += nand.o
OBJS    += serial.o
OBJS    += m41t11.o
OBJS    += irq_handler.o
OBJS    += lib/libc.a
 
CROSS_COMPILE := arm-linux-
CC            := $(CROSS_COMPILE)gcc
LD            := $(CROSS_COMPILE)ld
AR          := $(CROSS_COMPILE)ar
OBJCOPY        := $(CROSS_COMPILE)objcopy
OBJDUMP        := $(CROSS_COMPILE)objdump
 
#warning
INCLUDEDIR     := $(shell pwd)/include
CCFLAGS    += -nostdinc -I$(INCLUDEDIR)
CCFLAGS    += -Wall -O2
# 不加-O2优化,链接过程报错:
# lib/libc.a(string.o)(.text+0x38): In function `puts':
# : undefined reference to `putc'
 
#basic address
#ifeq ($(ENV), NAND)
#LDFLAGS    += -Ttext=0x0
#else
#LDFLAGS    += -Ttext=0xXXX
#endif
LDFLAGS    += -Tmap.lds
 
export     CC LD OBJCOPY OBJDUMP INCLUDEDIR CCFLAGS AR
 
#Compile way
all : $(DISA) $(TARGET)
$(DISA)    : $(BUILD)
    $(OBJDUMP) -D $^ > [email protected]
 
$(TARGET) : $(BUILD)
    $(OBJCOPY) -O binary -S $^ [email protected]
 
$(BUILD) : $(OBJS)
    $(LD) $(LDFLAGS) -o [email protected] $^
 
.PHONY : lib/libc.a
lib/libc.a:
    cd lib; make; cd ..
 
%.o : %.S
    $(CC) $(CCFLAGS) -c -o [email protected] $^
%.o : %.c
    $(CC) $(CCFLAGS) -c -o [email protected] $^
    
clean:
    make  clean -C lib
    rm -f $(TARGET) $(BUILD) $(DISA) *.o
其中加粗部分是为了将除法和取余运算的依赖库包含进来所执行的操作。
 
此外,为了实现时间参数的写入和读出,封装了几个有效的转换函数:
1、string -> int
/*
* pstr    : 字符串首地址,空字符结束
* len    : 字符串有效字符长度
*/
int str_to_int(const char *pstr, unsigned char len)
{
    unsigned int ret = 0;
    unsigned int mult;
    
    //根据pstr长度确定mult. E.G. pstr-1位 -> mult=1
    for (mult = 1; --len != 0; mult *= 10);
    
    for ( ;*pstr != '\0'; ++pstr)
    {
        ret += (unsigned int)(*pstr - '0') * mult;
        mult /= 10;
    }
 
    return (int)ret;
}
 
2、int -> string
/*
* val    : 需要转换的整形值
* bit    : 该整形值的位数
* pdst    : 转换字符串输出
*/
void int_to_str(int val, unsigned char bit, char *pdst)
{
    //根据val位数确定mult. E.G. val-1位 -> mult=1
    int mult;
    for (mult = 1; --bit != 0; mult *= 10);
 
    for ( ; mult != 0; mult /= 10)
    {
        *pdst++ = (char)(val/mult + '0');
        val %= mult;
    }
}
 
3、参数设置时间参数结构体变量, 将字符串类型的时间参数装换为对应的整形值
需要写入的时间参数格式:E.G.(year-mon-day-week-hour-min-sec): 2018 05 15 2 13 29 00,数值间以空格键分开
struct rtc_time {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_week;
    int tm_mday;
    int tm_mon;
    int tm_year;
};
void set_rtc_time(char *pstr, struct rtc_time *prtc)
{
    char *ptmp = pstr;
    char s_time[25];
    unsigned char i;
    unsigned char len[7] = {
     0};
    
    //1. 分拆时间字符串
    for ( i = 0; *ptmp != '\0';  ++ptmp)
    {
        if (*ptmp != ' ')
            len[i]++;
        else
        {
            *ptmp = '\0';
            ++i;
        }
    }
 
    //2. 设置对应rtc时间参数
    send_l(pstr);
    prtc->tm_year = str_to_int(pstr, len[0]);
    pstr += len[0] + 1;
    prtc->tm_mon = str_to_int(pstr, len[1]);
    pstr += len[1] + 1;
    prtc->tm_mday = str_to_int(pstr, len[2]);
    pstr += len[2] + 1;
    prtc->tm_week = str_to_int(pstr, len[3]);
    pstr += len[3] + 1;
    prtc->tm_hour = str_to_int(pstr, len[4]);
    pstr += len[4] + 1;
    prtc->tm_min = str_to_int(pstr, len[5]);
    pstr += len[5] + 1;
    prtc->tm_sec = str_to_int(pstr, len[6]);
}
void set_time(void)
{
    char s_time[30] = {
     0};
    send_l("E.G.(year-mon-day-week-hour-min-sec): 2018 5 15 2 13 29 0");
    recv_l(s_time);
    send_s("Input: ");
    send_l(s_time);
    set_rtc_time(s_time, &g_rtc_time);
    m41t11_set_datetime(&g_rtc_time);
}
由于时钟芯片m41t11可能不能正常工作(写入时间无效),故修改set_rtc_time函数作为测试函数如下
void set_rtc_time(char *pstr, struct rtc_time *prtc)
{
    char *ptmp = pstr;
    char s_time[25];
    unsigned char i;
    unsigned char len[7] = {
     0};
    
    //1. 分拆时间字符串
    for ( i = 0; *ptmp != '\0';  ++ptmp)
    {
        if (*ptmp != ' ')
            len[i]++;
        else
        {
            *ptmp = '\0';
            ++i;
        }
    }
 
    //2. 设置对应rtc时间参数
    send_l(pstr);
    prtc->tm_year = str_to_int(pstr, len[0]);
    pstr += len[0] + 1;
    send_l(pstr);
    prtc->tm_mon = str_to_int(pstr, len[1]);
    pstr += len[1] + 1;
    send_l(pstr);
    prtc->tm_mday = str_to_int(pstr, len[2]);
    pstr += len[2] + 1;
    send_l(pstr);
    prtc->tm_week = str_to_int(pstr, len[3]);
    pstr += len[3] + 1;
    send_l(pstr);
    prtc->tm_hour = str_to_int(pstr, len[4]);
    pstr += len[4] + 1;
    send_l(pstr);
    prtc->tm_min = str_to_int(pstr, len[5]);
    pstr += len[5] + 1;
    send_l(pstr);
    prtc->tm_sec = str_to_int(pstr, len[6]);
    get_rtc_time(&g_rtc_time, s_time);
    send_s("g_rtc_time: ");
    send_l(s_time);
}
 
3、读取时间参数结构体变量,并将其装换为字符串
void get_rtc_time(const struct rtc_time *prtc, char *pdst)
{
    //格式: 2018-05-15 2 19:30:00
    int_to_str(prtc->tm_year, 4, pdst);
    *(pdst+4) = '-';
    int_to_str(prtc->tm_mon, 2, pdst+5);
    *(pdst+7) = '-';
    int_to_str(prtc->tm_mday, 2, pdst+8);
    *(pdst+10) = ' ';
    int_to_str(prtc->tm_week, 1, pdst+11);
    *(pdst+12) = ' ';
    int_to_str(prtc->tm_hour, 2, pdst+13);
    *(pdst+15) = ':';
    int_to_str(prtc->tm_min, 2, pdst+16);
    *(pdst+18) = ':';
    int_to_str(prtc->tm_sec, 2, pdst+19);
    *(pdst+21) = '\0';
}
 
void show_time(void)
{
    //格式: 2018-05-15 2 13:29:00
    char s_time[25] = {
     0};
    send_s("Now is: ");
    m41t11_get_datetime(&g_rtc_time);
    get_rtc_time(&g_rtc_time, s_time);
    send_l(s_time);
}
 
最终实现的效果如下:
1、菜单界面
          
2、[R]ead  data&time.
            
3、[W]rite data&time.
      
从以上结果可以看出,int 与 string 之间的转换函数均可正常工作。
其中最后一行的 g_rtc_time 参数,是逆向转换后的输出结果,能够说明写入m41t11时钟芯片的参数没有问题
m41t11_set_datetime(&g_rtc_time);
不过之后读出的结果并没有发生改变:
      
故猜测可能是由于m41t11时钟芯片原因所致(不过纽扣电池电量不足应该可以排除,否则应该不能从中读出数据吧?这个并没有兴趣折腾了)

转载于:https://www.cnblogs.com/Glory-D/p/9062245.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34024034/article/details/94548357

智能推荐

dynamicCondition后台拼接sql_xiaozaq的博客-程序员宅基地

基于layui的动态添加条件查询ui插件码云:插件主页 高级查询插件下载有很多人问php后台拼接sql的代码怎么写。我这里分享一下java后台拼接sql代码给大家参考下。支持嵌套条件查询:/*** * 构造对应的查询条件语句以及添加动态参数到list列表 * @param listQueryCondition * @param list * @return */ public String superBuildSqlWhereNew(List&lt;QueryCo..

MarkDown 代码块_O漫步星海的博客-程序员宅基地_markdown 代码块

MarkDown 代码块1、代码行单行代码引用使用单个符号,反引号(`),就是英文状态下的波浪线。(符号位于 ESC 键下方)`我是代码行`我是代码行2、代码块用三个反引号(`)定义段开始和结束````# 显示需要加 # ,Markdown中不需要加代码块代码块```# 显示需要加 # ,Markdown中不需要加````代码块代码块3、代码块高亮首行三个单引号后面指定所用的语言后就可以实现代码块高亮了,...

PHP 获取类 / 对象的属性字段及属性值_chennutou1145的博客-程序员宅基地

get_class_vars获取类的公有属性及默认值(包含公有的静态属性),用来列举类的公有属性字段。get_object_vars获取对象的公有属性及属性值(不包含公有的静态属性)。ReflectionClass如果想要获取对象的各类属性(public/protected/priv...

MAC OS下使用OpenSSL生成私钥和公钥的方法_Chris1004的博客-程序员宅基地

MAC OS自带了OpenSSL,所以不用去编译那一坨跟SHIT一样的源码。直接在命令行里使用OPENSSL就可以。打开命令行工具,然后输入openssl打开openssl,接着只要三句命令就可以搞定。第一句命令生成私钥;第二句命令把RSA私钥转换成PKCS8格式,密码为空就行;第三句命令生成公钥。Last login: Fri Sep 12 00:59:51 on ttys000

jboss 下配置https_健康平安的活着的博客-程序员宅基地

1.      生成证书C:\Users\dinfo>cd C:\Program Files\Java\jdk1.7.0_09C:\Program Files\Java\jdk1.7.0_09>cd jreC:\Program Files\Java\jdk1.7.0_09\jre>cd binC:\Program Files\Java\jdk1.7.0_09\jre\bin>key

PHP绘图入门以及JPGraph库的使用_php攻城师的博客-程序员宅基地_jpgraph php绘图

php绘图的坐标系统(X轴向右,Y轴向下)1.      php绘图的基本原理和步骤l  创建画布l  绘制需要的各种图形(圆,直线,矩形,弧线,扇形...)l  输出图像到网页,也可以另存l  销毁该图片(释放内存)  ☞ 目前网站开发常见的图片格式有gif  jpg/jpeg  png bmp ....l  gif 图片压缩率高,但是只能显示256色

随便推点

toString方法和valueOf方法以及Symbol.toPrimitive方法的学习_baoleilei6的博客-程序员宅基地

valueOf()方法和toString()方法介绍valueOf()方法和toString()我们知道在js中,'一切皆为对象'。每个对象都有一个toString()方法和value方法,其中toString()方法返回一个表示该对象的字符串,value方法返回该对象的原始值。对于toString方法来说,当对象被表示为文本值或者当以期望字符串的方式引用对象时。该方法被自动调用。对于一个对...

php防止短时间内重复提交。_北方的刀郎的博客-程序员宅基地

//lyy防止短时间内重复提交 header("Content-type:text/html;charset=utf-8"); if(isset($_COOKIE['order'])&&$_COOKIE['order']==1){ echo " alert('对不起您已经提交过了,请勿重复提交!'); window.history.go(-1);"; exit; }else{

Andfix热修复_黯然泪的博客-程序员宅基地

一、什么是热修复热修复说白了就是”打补丁”,比如你们公司上线一个app,用户反应有重大bug,需要紧急修复。如果按照通 常做法,那就是程序猿加班搞定bug,然后测试,重新打包并发布。这样带来的问题就是成本高,效率低。于是,热修复就应运而生.一般通过事先设定的接口从网上下载无Bug的代码来替换有Bug的代码。这样就省事多了,用 户体验也好。二、热修复的原理1.Androi

如何使用Total Recorder录制软件发出的声音_b10l07的博客-程序员宅基地

1 打开Total Recorder的选项,点击系统设置,在弹出的声音选项卡中把Total Recorder扬声器设为默认(选中该项再点击默认,如果第一个扬声器选项还保存着&quot;默认通信设备&quot; 的字样,则右击第三个扬声器,再勾选他为&quot;默认通信设备&quot;,确保绿色的对勾只有红圈标出来的一项) 注意修改之后桌面右下角的喇叭可能会显示为错误图标,但是能放出声音,如图所示  2 在录制选项卡中...

.net平台的rabbitmq使用封装_weixin_30526593的博客-程序员宅基地

.net平台的rabbitmq使用封装前言  RabbitMq大家再熟悉不过,这篇文章主要整对rabbitmq学习后封装RabbitMQ.Client的一个分享。文章最后,我会把封装组件和demo奉上。Rabbitmq的关键术语  1、绑定器(Binding):根据路由规则绑定Queue和Exchange。  2、路由键(Routing Key):Exc...

推荐文章

热门文章

相关标签