马老师 请教你164的问题?
我在IAR里按马老师的164弄个测试的东西。结果不行。#define HC164_data PORTE_Bit7//PORTE_Bit7
#define HC164_clkPORTE_Bit6//
void HC164_send_byte(unsigned char byte)//定义函数 吧一个字节的数据串行发送到74hc164 程序运行成功了.
{
unsigned char i;
for(i=0;i<=7;i++)
{
HC164_data=byte & 1<<i;//machao
//if (byte & 1<<i)
//HC164_data = 1;
//else
//HC164_data = 0;
HC164_clk=1;
_NOP();
_NOP();
_NOP();
_NOP();
//_NOP();
HC164_clk=0;
}
}
在主程序这样用的
HC164_clk=0; //164 init
//164 scan
{
temp=0xfe; //赋显示初值
for(n=0;n<8;n++)
{
HC164_send_byte(temp); //写数据,送显示
DelayNms(500);
temp<<=1; //准备下一个显示数据
//temp=temp|0x01; //最低位置1
}
HC164_send_byte(0xff); //关闭显示
DelayNms(500);
}
后来在网络上找个就可以了。
请马老师指教。难道是我哪里不对--- http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_696069IFQ2TG.jpg
(原文件名:164.jpg) 没有买过马老师的书,看马老师的程序我记得是CVAVR的吧,支持单个位操作
没用过IAR,不知道是否支持单个位操作的,如果不支持,看下是不是这个问题
另外:记得前两天也有人问马老师164的问题…… 这么简单的代码你自己都不能分析吗? 其实我认识LZ,就是让马老师编个 按键 单击 双击程序的那位 你的图是不是有问题。
你这个是高电平把灯点亮啊。 回复【3楼】machao
-----------------------------------------------------------------------
我试着改了一晚上,该不通啊。所以才来了这里请教。我也很慎重的 回复【5楼】rising_sun
-----------------------------------------------------------------------
是的, 回复【4楼】ijlc1314 夜猫
-----------------------------------------------------------------------
我也看了哪些帖子,问的是C的问题,但是我实际试验的时候出了问题。
大侠好像把我记住了。罪过啊 HC164_data=byte & 1<<i;//machao
经过测试这个有问题,在IAR里
if (byte & 1<<i) //ok
HC164_data = 1;
else
HC164_data = 0;
下面这个就可以。
这个是谁的错? 回复【8楼】jacky82512
-----------------------------------------------------------------------
大侠……要我折寿哦,我也是刚刚学的AVR来的,不过我用的是WinAVR
建议你用书中使用的编译器吧。我觉得不要在编译器上花费太多时间。 回复【9楼】jacky82512
-----------------------------------------------------------------------
你自己的错,谁叫你自己不去了解好编译器的 if (byte & 1<<i)
汗! 这个逻辑! HC164_data=byte & 1<<i;//
马老师你在书中这样写,164是不运行的。
byte & 1<<i;//
这个值 ? 回复【13楼】jacky82512
-----------------------------------------------------------------------
byte & 1<<i等于( byte & ( 1<<i ) )
这个没问题吧,我觉得主要是 左值是 bit变量,而右值不是,根本就不匹配, 编译器不同,结果也就不同了 在标准C中,没有bit(位)型的变量。在CVAVR中,BIT型变量是扩展的。
对于其它的一些编译器,比如ICC、GCC(WINAVR)都不支持BIT变量的。我记得老的IAR也不支持位变量的(我在查查看)。
如果你现在使用的IAR支持BIT变量,那么应该看看他的使用手册,了解如何支持和操作的。
简单的方法就是在AVR STUDIO中软件模拟一下,
执行 HC164_data = byte & 1<< i语句,看对应的I/O口输出是否对,另外,在AVR STUDIO中,直接看该语句对于的汇编代码,也可以知道原因是什么。 回复【1楼】jacky82512
-----------------------------------------------------------------------
照你这个图,如果164接的是5V,怎么可能亮灯? 1楼的图LED是会亮的,不过是164输出1点亮。LZ的硬件也太哪个了吧。 回复【17楼】machao
-----------------------------------------------------------------------
这个我已经注意到了。误以为那一极接5V了,结果是接地的。不好意思 弄不明白 怎么控制164从高到低怎么从低到高
if (byte & 1<<i) //ok
HC164_data = 1;
else
HC164_data = 0;
这样是从高到低 但是为什么是这样呢?
比如BYTE=0B1010 1010
i=0是0000 0001 位与byte HC164_data是0
最低位先给HC164_data
那为什么还是从高到低呢?不大理解
请高手点明。 "for(i=0;i<=7;i++)
{
HC164_data=byte & 1<<i;//machao
//if (byte & 1<<i)
//HC164_data = 1;
//else
//HC164_data = 0; "
that particular piece of code is not spi-compliant as it sends lsb first and msb last.
also "HC164_data=byte & 1<<i;//machao" also is poorly coded. 回复【20楼】millwood0
-----------------------------------------------------------------------
我e文好差,基本不能看懂。得有道翻译,翻译结果也都差强人意。
还是多谢了。millwood0 hc164不是标准的SPI接口,这个代码只是通过I/O口的模拟吧一个字节串出打入到HC164中,与SPI无关。
至于高位在前还是地位在前,这个都不是重要的,看你硬件的连接和实际的需要,只是简单的调整一下代码就可以了,这个没有什么死规定,是根据实际情况定的。关键是你是否掌握使用串行方式扩展成并行输出。
至于"HC164_data=byte & 1<<i; " 是否为“poorly coded”不是主要的,
难道“HC164_data = byte & (1<<i);就不是“poorly coded”啦,其实这句和上句是一样的。
关键是你是否掌握这句语句的作用。这个是你C语言掌握的水平问题。况且HC164_data=byte & 1<<i并不是什么非常难掌握和理解的语句。
你写的语句标准,可读性好只是锦上添花,真正的关键是你是否掌握思路和方法。 谢马老师。还是想搞明白。19楼的问题。是不是和164的逻辑结构有关系呢?
还是软件控制的?
比如BYTE=0B1010 1010
i=0是0000 0001 位与byte HC164_data是0
最低位先给HC164_data
那为什么还是从高到低呢?不大理解 假定你1楼的图接线是164的D7接LED的D0,164的D0接LED的D7,8根连接反一下,程序应该如何变化? 现在的人更加是聪明了,还是笨了?搞不懂。这么一个小的变化都转不来。我已经解释的非常清楚了。 "比如BYTE=0B1010 1010"
it sends the lowest bit first - when it works.
so in this case, you send 0b1010 1010 (0xaa) and get 0b0101 0101 (0x55) on hc164. here is a quick exercise that I did.
=============example================
#include <ioavr.h> //we use iar avr
//hardware configuration
#define HC164_PORT PORTE
#define HC164_DDR DDRE
#define HC164_CLK (1<<0)
#define HC164_MOSI (1<<1)
#define HC164_CLK_PIN PORTE_Bit0
#define HC164_MOSI_PIN PORTE_Bit1
//end hardware configuration
void hc164_init(void) {
HC164_PORT &=~(HC164_CLK | HC164_MOSI); //clear clk/mosi
HC164_DDR |= (HC164_CLK | HC164_MOSI); //clk / mosi as output
}
void hc164_write(unsigned char dat) {
unsigned char mask = 0x80; //mask, msb first
//HC164_PORT &=~(HC164_CLK | HC164_MOSI); //clear clk/mosi
//HC164_DDR |= (HC164_CLK | HC164_MOSI); //clk / mosi as output
do {
HC164_PORT &=~HC164_CLK; //clear clk
if (dat & mask) HC164_PORT |= HC164_MOSI; //send 1
else HC164_PORT &=~HC164_MOSI; //send 0
HC164_PORT |= HC164_CLK; //set clk
mask = mask >> 1; //send the next bit
} while (mask); //send all bits
//HC164_PORT &=~HC164_CLK; //reset clk - optional
}
void hc164_write2(unsigned char dat) {
unsigned char i;
for (i=0; i<8; i++) {
//HC164_MOSI_PIN = dat & (1<<i); //send bits
HC164_MOSI_PIN = (dat & (1<<i))? 1: 0;
HC164_CLK_PIN=1; //send clock
HC164_CLK_PIN=0; //clear clock
}
}
int main( void )
{
hc164_init(); //reset the hc164
//send 1st byte
HC164_PORT |= HC164_MOSI; //indicates the start of the transmission
hc164_write(0xaa); //send a byte
HC164_PORT |= HC164_MOSI; //indicates the end of the transmission
//send 2nd byte
HC164_PORT &=~HC164_MOSI; //indicates the start of the transmission
hc164_write2(0xaa); //send a byte
HC164_PORT &=~HC164_MOSI; //indicates the end of the transmission
while (1) {
}
return 0;
}
=========================
the above code implements two hc164 write routines, hc164_write() and hc164_write2().
hc164_write() uses masks and sends the most significant bit first, consistent with the spi standard.
hc164_write2() is your implementation - it uses a for () loop, and bit shifts and sends the least significant bit first.
*****notice that change I did in the particular implementation and I will come back there**********************
the hc164_write() sends the byte (0xaa) in 135us, and the bits show up correctly on hc164 (as 0xaa).
the hc164_write2() sends the byte (0xaa) in 470us, and the bits show up incorrectly on hc164 (as 0x55).
http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_696597F2HUMM.PNG
(原文件名:avr hc164.PNG) here is the change I did in your hc164_write2() routine:
" //HC164_MOSI_PIN = dat & (1<<i); //send bits
HC164_MOSI_PIN = (dat & (1<<i))? 1: 0;"
"HC164_MOSI_PIN = dat & (1<<i);" does not work under iar ewavr. C does not define bit operations. as such its implementation is uncertain and compiler dependent. "HC164_MOSI_PIN = dat & (1<<i);" for example works for gcc avr but not iar avr.
the correct implementation is to test (dat & (1<<i)) explicitly and then assign 1 or 0 to your output pin based on the test, as I did there.
a fancier implementation of this, which works on all C89 compilers, is "HC164_MOSI_PIN = !(!(dat & (1<<i)));" the point here is that a) youhave to write code as much portable / readable and standard-compliant as you can; and b) try to rely as little on compiler extensions as you can.
that means don't use bit variables and use masks as much as you can. here is the result of your code, using "HC164_MOSI_PIN = dat & (1<<i); //send bits "
void hc164_write2(unsigned char dat) {
unsigned char i;
for (i=0; i<8; i++) {
HC164_MOSI_PIN = dat & (1<<i); //send bits
//HC164_MOSI_PIN = (dat & (1<<i))? 1: 0;
//HC164_MOSI_PIN = !(!(dat & (1<<i))); //send bits
HC164_CLK_PIN=1; //send clock
HC164_CLK_PIN=0; //clear clock
}
}
http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_696600U301OZ.PNG
(原文件名:avr hc164 2.PNG)
页:
[1]